TypeScript 的条件类型
Conditional types with TypeScript
假设我有这个:
type TypeMapping = {
Boolean: boolean,
String: string,
Number: number,
ArrayOfString: Array<string>,
ArrayOfBoolean: Array<boolean>
}
export interface ElemType {
foo: keyof TypeMapping,
default: valueof TypeMapping
}
而不是默认使用any
,我想有条件地定义它,我试过这个:
export interface ElemType<T extends TypeMapping> {
foo: keyof T,
default: T
}
但这似乎不太正确,有谁知道正确的做法吗?
如果不清楚,对于任何具有 ElemType 类型的给定对象,foo 指向的键必须与 foo 指向的值相匹配。例如,这是有效的:
{
foo: 'String',
default: 'this is a string'
}
但这不是:
{
foo: 'Boolean',
default: 'this should be a boolean instead'
}
所以默认字段的类型是 conditional on the value/type of the type field.
简洁,如果foo
是'ArrayOfBoolean'
,那么default
应该是:Array<boolean>
。如果 foo
是 'Number'
,那么默认应该是 number
,如果 foo 是 'Boolean'
那么默认应该是 boolean
,等等
你必须告诉打字稿以某种方式验证实际的对象,如果不使用泛型你就无法真正逃脱;我会这样做:
type TypeMapping = {
Boolean: boolean;
String: string;
Number: number;
ArrayOfString: Array<string>;
};
export interface ElemType<K extends keyof TypeMapping> {
foo: K;
default: TypeMapping[K];
}
const Elem = <E extends keyof TypeMapping, T extends ElemType<E>>(t: ElemType<E>) => t;
Elem({ foo: "Boolean", default: true }); //yup
Elem({ foo: "Boolean", default: "" }); //nope
您可以按照 Catalyst 的回答定义 ElemType
,然后使用映射类型为所有可能的 K
:
获取 ElemType
的并集
interface ElemType<K extends keyof TypeMapping> {
foo: K;
default: TypeMapping[K];
}
type ElemTypeMap = {[K in keyof TypeMapping]: ElemType<K>};
// type ElemTypeMap = {
// Boolean: {foo: "Boolean", default: boolean},
// String: {foo: "String", default: string},
// ...
// }
type SomeElemType = ElemTypeMap[keyof TypeMapping];
// Look up in ElemTypeMap by all keys and take the union:
// {foo: "Boolean", default: boolean} | {foo: "String", default: string} | ...
假设我有这个:
type TypeMapping = {
Boolean: boolean,
String: string,
Number: number,
ArrayOfString: Array<string>,
ArrayOfBoolean: Array<boolean>
}
export interface ElemType {
foo: keyof TypeMapping,
default: valueof TypeMapping
}
而不是默认使用any
,我想有条件地定义它,我试过这个:
export interface ElemType<T extends TypeMapping> {
foo: keyof T,
default: T
}
但这似乎不太正确,有谁知道正确的做法吗?
如果不清楚,对于任何具有 ElemType 类型的给定对象,foo 指向的键必须与 foo 指向的值相匹配。例如,这是有效的:
{
foo: 'String',
default: 'this is a string'
}
但这不是:
{
foo: 'Boolean',
default: 'this should be a boolean instead'
}
所以默认字段的类型是 conditional on the value/type of the type field.
简洁,如果foo
是'ArrayOfBoolean'
,那么default
应该是:Array<boolean>
。如果 foo
是 'Number'
,那么默认应该是 number
,如果 foo 是 'Boolean'
那么默认应该是 boolean
,等等
你必须告诉打字稿以某种方式验证实际的对象,如果不使用泛型你就无法真正逃脱;我会这样做:
type TypeMapping = {
Boolean: boolean;
String: string;
Number: number;
ArrayOfString: Array<string>;
};
export interface ElemType<K extends keyof TypeMapping> {
foo: K;
default: TypeMapping[K];
}
const Elem = <E extends keyof TypeMapping, T extends ElemType<E>>(t: ElemType<E>) => t;
Elem({ foo: "Boolean", default: true }); //yup
Elem({ foo: "Boolean", default: "" }); //nope
您可以按照 Catalyst 的回答定义 ElemType
,然后使用映射类型为所有可能的 K
:
ElemType
的并集
interface ElemType<K extends keyof TypeMapping> {
foo: K;
default: TypeMapping[K];
}
type ElemTypeMap = {[K in keyof TypeMapping]: ElemType<K>};
// type ElemTypeMap = {
// Boolean: {foo: "Boolean", default: boolean},
// String: {foo: "String", default: string},
// ...
// }
type SomeElemType = ElemTypeMap[keyof TypeMapping];
// Look up in ElemTypeMap by all keys and take the union:
// {foo: "Boolean", default: boolean} | {foo: "String", default: string} | ...