假设我有一个字典,将组件名称映射到实际组件,如下所示:-
const FC1 = ({prop} : {prop: number}) => <>{prop}</>;
const FC2 = ({prop} : {prop: string}) => <>{prop}</>;
const mapComponents = [
{type : "Functional Component 1", element : FC1},
{type : "Functional Component 2", element : FC2}
]
我有一个辅助函数来构造所需的元素,如下所示:-
const ConstructComponent = ({type, props}: {type : string, props? : any}) => {
for(const x of mapComponents){
if(x.type === type){
return <x.element {...props}/>
}
}
return null
}
这样,我可以使用jsx表达式轻松地调用地图中的任何组件
<ConstructElement type="Functional Component 1" props={{prop1 : 123}}/>
我想使其尽可能地安全。我知道可以通过手动创建像这样的类型来实现:-
type ConstructComponentProps = ({type : "Functional Component 1", props : React.ComponentProps<typeof FC1>}) | ({type : "Functional Component 2", props : React.ComponentProps<typeof FC2>})
这是我的问题:-
1)是否有更简单的方法来实现这一目标?我在想能够从mapComponents常量自动推断类型的思路。我知道这行不通,但是类似:-
type ConstructComponentProps = mapComponents.map((obj) => {type : obj.type, props: React.ComponentProps<typeof obj.element>})
2)我可以这种格式获取'type'属性的所有可能值吗?这样的东西让我像:-
type types = "Functional Component 1" | "Functional Component 2"
答案 0 :(得分:0)
1)
const FC1 = ({prop} : {prop: number}) => <>{prop}</>;
const FC2 = ({prop} : {prop: string}) => <>{prop}</>;
const mapComponents = {
"Functional Component 1": FC1,
"Functional Component 2": FC2
};
type MapComponents = typeof mapComponents;
type PropsOf<T> = T extends React.ComponentType<infer P> ? P : never;
function ConstructComponent <T extends keyof MapComponents, P extends PropsOf<MapComponents[T]>>({type, props}: {type: T, props?: P}) {
for(const x in mapComponents){
if(x === type){
const Component = mapComponents[x];
return <Component {...props} />;
}
}
return null;
}
此<ConstructComponent type="Functional Component 2" props={{prop: 123}} />
会引发以下错误:The expected type comes from property 'prop' which is declared here on type '{ prop: string; }'
,因为类型Functional Component 2
期望一个名为prop
的字符串类型的道具。
2)通过将mapComponents
更改为对象,可以获取其键
答案 1 :(得分:0)
如果要保留type
元素的mapComponents
属性的string literal类型,则需要告诉编译器不要将它们扩展为{{1} },这是默认行为。从TS3.4开始,您可以使用const
assertion来请求尽可能窄的推断类型:
string
执行此操作后,便可以从中建立所需的类型。这是确定const mapComponents = [
{ type: "Functional Component 1", element: FC1 },
{ type: "Functional Component 2", element: FC2 }
] as const
的方法:
ConstructComponentProps
这可以通过使用distributive conditional type(这是type _ConstructComponentProps<C extends typeof mapComponents[number] =
typeof mapComponents[number]> = C extends any ?
{ type: C["type"], props: React.ComponentProps<C["element"]> } : never;
type ConstructComponentProps = _ConstructComponentProps
/* type ConstructComponentProps = {
type: "Functional Component 1";
props: {
prop: number;
};
} | {
type: "Functional Component 2";
props: {
prop: string;
};
} */
语法,其中C extends any ? ...
是通用类型参数)来将C
的元素联合分解为各个部分并对其进行操作。还有其他方法可以执行此操作,但是它们都将以某种形式涉及条件类型。
然后您的mapComponents
是一个简单的lookup:
Types
好的,希望能有所帮助;祝你好运!