是否有可能推断第一个子元素的props 并在TypScript中强制执行它们?我可以接近它,但它在仿制药中开始失败,而且我还无法推断出类型.

我正在try 将组件props 从包装器传递到具有类型安全性的第一个子组件.当对象上不存在props 时,TS应该失败,否则通过.

import React, {
  Children,
  isValidElement,
  cloneElement,
  ReactNode,
} from 'react';

interface WrapperProps<C> {
  children: ReactNode;
  // how can I make typeof Button generic/inferred from the code?
  // firstChildProps: Partial<React.ComponentProps<typeof Button>>; // works with <C> removed
  firstChildProps: Partial<React.ComponentPropsWithoutRef<C>>;
}

const Wrapper: React.FC<WrapperProps<typeof Button>> = ({
  children,
  firstChildProps,
}) => {
  const firstChild = Children.toArray(children)[0];
  if (isValidElement(firstChild)) {
    // Clone the first child element and pass the firstChildProps to it
    return cloneElement(firstChild, { ...firstChildProps });
  } else {
    return <>{children}</>;
  }
};

interface ButtonProps {
  disabled: boolean;
  children: ReactNode;
}

const Button: React.FC<ButtonProps> = ({ disabled, children }) => {
  return <button disabled={disabled}>{children}</button>;
};

const Example = () => {
  return (
    <>
      {/* Passes type check because disabled exists on Button */}
      <Wrapper firstChildProps={{ disabled: false }}>
        <Button disabled={true}>Ok</Button>
      </Wrapper>
      {/* Fails type check because cheese does not exist on Button */}
      <Wrapper firstChildProps={{ cheese: true }}>
        <Button disabled={true}>Ok</Button>
      </Wrapper>
    </>
  );
};

这是一个接近工作的TS Playground.

推荐答案

  1. 您需要约束C通用类型参数,以便它适合ComponentProps实用类型,例如ElementType,正如SlavaSobolev的回答中所建议的那样:
interface WrapperProps<C extends React.ElementType> {
    children: ReactNode;
    firstChildProps: Partial<React.ComponentPropsWithoutRef<C>>;
}
  1. 您也可以将Wrapper组件设为通用组件,但您必须删除React.FC,因为它不适用于进一步的通用组件:
const Wrapper = <C extends React.ElementType>({ children, firstChildProps }: WrapperProps<C>) => {
  // etc.
}

然后您可以将其用于不同的内容:

interface OtherProps {
    foo: "bar";
}

const Other: React.FC<OtherProps> = () => null;

{/* Fails type check because cheese does not exist on Button */}
<Wrapper<typeof Button> firstChildProps={{ cheese: true }}>
    <Button disabled={true}>Ok</Button>
</Wrapper>

{/* Error: Type 'number' is not assignable to type '"bar"'. */}
<Wrapper<typeof Other> firstChildProps={{ foo: 0 }}>
    <Other foo="bar" />
</Wrapper>

Playground Link

Javascript相关问答推荐

Angular material 表多个标题行映射

如何通过继承contentitable属性的元素捕捉keydown事件?

强制执行useStatego struct 化变量[foo,setFoo]的命名约定?

我的服务工作器没有连接到我的Chrome扩展中的内容脚本.我该怎么解决这个问题?

我在我的Java代码中遇到了问题,代码的一部分看不到先前定义的对象

简单的PayPal按钮集成导致404错误

使用Promise.All并发解决时,每个promise 的线性时间增加?

在HTML语言中调用外部JavaScript文件中的函数

如何发送从REST Api收到的PNG数据响应

以编程方式聚焦的链接将被聚焦,但样式不适用

为什么在函数中添加粒子的速率大于删除粒子的速率?

当我点击一个按钮后按回车键时,如何阻止它再次被点击

判断函数参数的类型

JavaScript&;Reaction-如何避免在不使用字典/对象的情况下出现地狱?

我无法在Api Reaction本机上发出GET请求

ComponentWillReceiveProps仍在React 18.2.0中工作

固定动态、self 调整的优先级队列

有角粘桌盒阴影

将Windows XP转换为原始数据以在html前端中显示

如何使用useparams从react路由中提取id