rfc 中类型推导部分 Type Inference
预期想实现的效果
createComponent({ props: { foo: { type: String, required: true }, bar: { type: Number }, boo: Boolean, options: (null as any) as { msg: string }, requiredOptions: { type: (null as any) as { msg: string }, required: true } } as const, setup(props) { props.foo; // string props.bar; // number | undefined props.boo; // boolean | undefined props.options; // {msg: string } | undefined props.requiredOptions; // {msg: string } }});
String
-> string
、 Number
-> number
、 Boolean
-> boolean
在 ts 中
String
对应的类型是StringConstructor
Number
对应的类型是NumberConstructor
Boolean
对应的类型是BooleanConstructor
但是,我们想要实现的是转换成小写的string | number | boolean
所以我们写个泛型来转换
type NormalizeType<T> = T extends StringConstructor ? string : T extends NumberConstructor ? number : T extends BooleanConstructor ? boolean : T;
playground 预览链接
定义 prop 的类型
type BuiltInType<T> = | StringConstructor | NumberConstructor | BooleanConstructor | T;
留个泛型是给复杂类型做兼容
rfc 复杂的 prop 类型
定义createComponent
函数接收的props
类型
type DefaultType<T> = { [key: string]: | { type?: BuiltInType<T>; require?: boolean; } | BuiltInType<T>;};
最关键的一步根据输入的props
类型计算出来setup
函数接收的形参props
类型
type ReflexType<T> = { [key in keyof T]: T[key] extends { type: infer TYPE; required: true } ? NormalizeType<TYPE> : T[key] extends { type: infer TYPE } ? NormalizeType<TYPE> | undefined : NormalizeType<T[key]> | undefined};
组合出来createComponent
函数定义
function createComponent<T extends DefaultType<any>>(props: { props: T; setup(props: ReflexType<T>): any;}) {}
完整代码
type BuiltInType<T> = | StringConstructor | NumberConstructor | BooleanConstructor | T;type NormalizeType<T> = T extends StringConstructor ? string : T extends NumberConstructor ? number : T extends BooleanConstructor ? boolean : T;type ReflexType<T> = { [key in keyof T]: T[key] extends { type: infer TYPE; required: true } ? NormalizeType<TYPE> : T[key] extends { type: infer TYPE } ? NormalizeType<TYPE> | undefined : NormalizeType<T[key]> | undefined};type DefaultType<T> = { [key: string]: { type?: BuiltInType<T>; require?: boolean } | BuiltInType<T>;};function createComponent<T extends DefaultType<any>>(props: { props: T; setup(props: ReflexType<T>): any;}) {}createComponent({ props: { foo: { type: String, required: true }, bar: { type: Number }, boo: Boolean, options: (null as any) as { msg: string }, requiredOptions: { type: (null as any) as { msg: string }, required: true } } as const, setup(props) { props.foo; props.bar; props.boo; props.options; props.requiredOptions; }});
playground 预览链接