TypeScript中表单配置构建器的类对象类型动态推断问题
表单配置构建器的TypeScript类型推断问题
问题背景
我正在构建一个表单配置构建器,希望能动态推断类型,以下是最小复现代码:
interface Meta { optional: boolean } class Base<Type = any> { readonly _type!: Type baseMeta: Meta constructor() { this.baseMeta = { optional: false, } } optional() { this.baseMeta.optional = true return this; } } class FieldText extends Base<string> { } class FieldNumber extends Base<number> { } class Field { static text() { return new FieldText(); } static number() { return new FieldNumber(); } } const fields = { fieldText: Field.text(), fieldNumber: Field.number(), fieldTextOptional: Field.text().optional(), fieldNumberOptional: Field.number().optional(), }
期望的类型结果
希望实现以下两种类型之一:
type ExpectedType = { fieldText: string; fieldNumber: number; fieldTextOptional: string | undefined; fieldNumberOptional: number | undefined; }
或者:
type ExpectedTypeWithOptionalKeys = { fieldText: string; fieldNumber: number; fieldTextOptional?: string; fieldNumberOptional?: number; }
尝试的方案及问题
我尝试进行类型推断,但optional属性未被纳入考量:
type ExtractFieldType<O, T> = O extends true ? T | undefined : T; type SchemaType<T extends Record<string, Base>> = { [Property in keyof T]: ExtractFieldType<T[Property]['baseMeta']['optional'], T[Property]['_type']>; }; type Schema = SchemaType<typeof fields>;
当前Schema的结果为:
type Schema = { fieldText: string; fieldNumber: number; fieldTextOptional: string; fieldNumberOptional: number; }
其中O extends true ? T | undefined : T始终返回T,未考虑optional的实际值。
最终实现方案
参考@kelly的回答调整optional函数后,最终实现如下:
optional<T extends boolean>(value?: T): Base<Type, T> { const optional = typeof value === 'boolean' ? value : true; this.baseMeta.optional = optional as boolean; return this as unknown as Base<Type, T>; }
最初无法设置默认值,否则TypeScript会报错:
Type 'boolean' is not assignable to type 'T'. 'boolean' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'boolean'.(2322)
因此将value设为可选参数,其余部分按说明实现,若移除as unknown会出现以下错误:
Conversion of type 'this' to type 'Base<Type, T>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Type 'Base<Type, boolean>' is not comparable to type 'Base<Type, T>'. Type 'boolean' is not comparable to type 'T'. 'boolean' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'boolean'.(2352)
内容的提问来源于stack exchange,提问作者Mykolas
相关产品推荐
相关产品推荐

