我正在制作一个React组件,它接受一系列其他React组件及其props .

type Components = [ComponentType, Props][]

我怎样才能写这个,以便类型脚本能够理解Props对象应该匹配给定的组件props ?

谢谢.

UPD,基本上,一个函数接受一个[fn,args]数组,并用相应的args调用每个fn.如何编写该函数的签名,以便二元组是类型安全的正确fn/arg对?

推荐答案

您可以做到这一点,尽管它有点复杂,并且在当前的实现中比我希望的更脆弱.我已经将类型逻辑抽象为助手类型:

// This part is reusable for any pair of [unaryFunction, argument]
type IsFnArgPair<T extends any> = T extends [infer F, infer A] ? F extends (x: A) => any ? T : [never, never] : [never, never]

function RenderChildPropPairs<T extends any[]>(props: { pairs: Array<IsFnArgPair<T>> }): JSX.Element {
  return (
    <>
      {props.pairs.map(([Comp, props]) => <Comp {...props} />)}
    </>
  );
}

我们可以定义几个组件/props 对来测试这一点:

type MyComponentProps = { children: React.ReactNode, foo: number }
function MyComponent(props:MyComponentProps): JSX.Element {
  return (
    <div>
      {String(props.foo)}
      {props.children}
    </div>
  );
}

type MyOtherComponentProps = {
  foo: boolean
}

function MyOtherComponent({ foo }: MyOtherComponentProps): JSX.Element {
  return <div>{String(foo)}</div>;
}

然后测试它:

function RenderPass() {
  // OK
  return <RenderChildPropPairs pairs={[[MyComponent, { foo: 1, children: null }], [MyOtherComponent, { foo: true }]]} />
}

function RenderFail() {
  // Fails as expected
  return <RenderChildPropPairs pairs={[[MyComponent, { foo:'hi', children: null }], [MyOtherComponent, { foo: 1 }]]} />
}

这并不完美.特别是,有两个方面您可以改进:更好的智能感知(传递无效对的人只会得到"类型blah不能分配给类型‘never’"",这不是一个很好的错误消息.第二个是,如果您试图将这些对提取到变量中,您会看到推断存在问题,尽管使用satisfies可以稍微减轻这个问题:

function LessOops() {
  const pairs = [[MyComponent, { foo: 1, children: null }], [MyOtherComponent, { foo: true }]] satisfies Array<[any, any]>;
  return <RenderChildPropPairs pairs={pairs} />
}

请注意,尽管是any s,但这仍然是类型安全的:如果您传递无效的对,您将收到错误.

此解决方案的另一个问题是,如果您try 使用as const将对数组输入为二元组,您会看到与as constreadonly度相关的错误.我会继续努力解决这个问题,尽管也许更聪明的人可以给出更好的解决方案.

Playground

Typescript相关问答推荐

如何传递基于TypScript中可变类型的类型?

类型是工作.但它失go 了正确变体的亮点..为什么?或者如何增强?

从接口创建类型安全的嵌套 struct

泛型和数组:为什么我最终使用了`泛型T []`而不是`泛型T []`?<><>

对深度对象键/路径进行适当的智能感知和类型判断,作为函数参数,而不会触发递归类型限制器

带占位符的模板文字类型何时扩展另一个?

如何在TypeScrip中从字符串联合类型中省略%1值

为什么我的条件类型不能像我预期的那样工作?

在分配给类型的只读变量中维护const的类型

如何在Type脚本中动态扩展函数的参数类型?

用于验证字符串变量的接口成员

嵌套对象的类型

TypeScrip:来自先前参数的参数中的计算(computed)属性名称

使用Redux Saga操作通道对操作进行排序不起作用

使用TypeScrip的类型继承

如何在省略一个参数的情况下从函数类型中提取参数类型?

将接口映射到交叉口类型

为什么 Typescript 无法正确推断数组元素的类型?

如何判断路由或其嵌套路由是否处于活动状态?

如何在 ngFor 循环中以Angular 正确动态渲染组件