从打字稿中的变量推断类型
Inferring types from a variable in typescript
假设我有一个将组件名称映射到实际组件的字典,如下所示:-
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"
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
改成一个对象,就可以得到它的keys
如果您想保留 string literal types of the type
properties of the elements of mapComponents
, you'll need to tell the compiler not to widen them to string
which is the default behavior. Since TS3.4 you can use a const
assertion 以请求尽可能窄的推断类型:
const mapComponents = [
{ type: "Functional Component 1", element: FC1 },
{ type: "Functional Component 2", element: FC2 }
] as const
完成此操作后,您就可以从中构建所需的类型。这是我确定 ConstructComponentProps
:
的方法
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;
};
} */
这通过使用 distributive conditional type(这是 C extends any ? ...
语法,其中 C
是泛型类型参数)将 [=14= 的元素并集分开] 分成单独的部分并对每个部分进行操作。还有其他方法可以做到这一点,但它们都会以某种形式涉及条件类型。
然后你的 Types
是一个简单的 lookup:
type Types = ConstructComponentProps["type"];
// type Types = "Functional Component 1" | "Functional Component 2"
好的,希望对您有所帮助;祝你好运!
假设我有一个将组件名称映射到实际组件的字典,如下所示:-
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"
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
改成一个对象,就可以得到它的keys
如果您想保留 string literal types of the type
properties of the elements of mapComponents
, you'll need to tell the compiler not to widen them to string
which is the default behavior. Since TS3.4 you can use a const
assertion 以请求尽可能窄的推断类型:
const mapComponents = [
{ type: "Functional Component 1", element: FC1 },
{ type: "Functional Component 2", element: FC2 }
] as const
完成此操作后,您就可以从中构建所需的类型。这是我确定 ConstructComponentProps
:
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;
};
} */
这通过使用 distributive conditional type(这是 C extends any ? ...
语法,其中 C
是泛型类型参数)将 [=14= 的元素并集分开] 分成单独的部分并对每个部分进行操作。还有其他方法可以做到这一点,但它们都会以某种形式涉及条件类型。
然后你的 Types
是一个简单的 lookup:
type Types = ConstructComponentProps["type"];
// type Types = "Functional Component 1" | "Functional Component 2"
好的,希望对您有所帮助;祝你好运!