[英]Typescript generic type for nested object properties
我想实现这样的事情,以便可以推断出Component
的类型,因此可以自动安全地键入props
。
type ComponentsType<T extends React.FC<any>> {
[key: string]: {
Component: T;
props?: React.ComponentProps<T>
};
}
const components: ComponentsType = {
RedButton: {
Component: Button,
props: { // <- this should be automatically typed to take props of Button
color: 'red'
}
},
BlueButton: {
Component: Button,
props: { // <- this should be automatically typed to take props of Button
color: 'blue'
}
},
FullWidthCard: {
Component: Card,
props: { // <- this should be automatically typed to take props of Card
variant: 'full-width'
}
},
}
但是上面的类型不起作用,因为通用部分在对象 AKA components
的根上,而不是在每个属性 AKA RedButton
或FullWidthCard
。
那么有没有办法让打字稿一一运行它们并一一推断组件?
谢谢
为了实现预期的行为,您需要从函数参数中推断每个组件和道具。 我的意思是,您需要创建一个额外的功能。
import React, { FC, ComponentProps } from 'react'
const Button: FC<{ color: string }> = (props) => null
const Card: FC<{ variant: string }> = (props) => null
type WithProps<T> =
T extends Record<infer Key, infer _> ? {
[P in Key]: T[Key] extends { Component: infer Comp, props: infer PassedProps }
? Comp extends React.JSXElementConstructor<infer Prps>
? { Component: Comp, props: ComponentProps<Comp> & Record<Exclude<keyof PassedProps, keyof Prps>, never> }
: never
: never
} : never
const components = <
Comp extends React.JSXElementConstructor<any>,
Item extends { Component: Comp },
Components extends Record<string, Item>>(dictionary: Components & WithProps<Components>) => {}
Comp
- 推断组件
Item
- 推断的字典项、 component&props
对象
Components
- 推断整个参数。
WithProps
- 遍历传递参数的每个对象并检查props
obhect 是否可分配给组件 props。 如果是 - 返回道具,否则将所有无效道具否定为never
。
components({
RedButton: {
Component: Button,
props: {
color: 'red'
}
},
BlueButton: {
Component: Button,
props: {
extra_prop:42, // DRAWBACK, no error
color: 'blue'
}
},
FullWidthCard: {
Component: Card,
props: {
variant_invalid_prop: 'full-width' // expected error
}
},
})
但是有一个缺点,这个函数会接受额外的道具,比如extra_prop
。
PS我希望有人能提出更好的解决方案,其中额外的道具也将无效
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.