如何利用Schema数组推断TypeScript对象类型
如何利用Schema数组推断TypeScript对象类型
嘿,我完全懂你的需求——不想手动重复写对象类型,而是希望通过已有的Schema数组自动推断出对应的TypeScript类型对吧?这确实能减少冗余代码,还能保证类型和Schema的一致性,咱们一步步来搞定它:
首先明确核心思路:把Schema里每个Field的name作为对象属性名,kind映射成TS原生类型,再根据required标记判断属性是必填还是可选。
第一步:定义Kind到TS类型的映射工具
先写一个工具类型,把Schema里的kind字符串转换成TypeScript的原生类型:
type KindToType<K extends Field['kind']> = K extends 'string' ? string : K extends 'integer' | 'float' ? number : K extends 'bool' ? boolean : never;
这个类型会根据传入的kind值返回对应TS类型——比如'integer'和'float'都对应number,'string'对应string,以此类推。
第二步:从Schema推断对象类型的核心工具
接下来写核心工具类型,接收Schema类型后生成对应的对象类型:
type InferFromSchema<S extends Schema> = // 处理必填字段:仅保留required为true的字段 { [F in S['fields'][number] as F['name']]: F extends { required: true } ? KindToType<F['kind']> : never } & // 处理可选字段:保留required为false或未定义的字段,标记为可选 { [F in S['fields'][number] as F['name']]?: F extends { required: true } ? never : KindToType<F['kind']> } extends infer O // 移除类型为never的无效属性,避免冗余 ? { [K in keyof O as O[K] extends never ? never : K]: O[K] } : never;
第三步:实际使用推断类型
现在就可以用这个工具类型来推断customer的类型了:
type Field = { name: string kind: 'string' | 'integer' | 'float' | 'bool' required?: boolean } type Schema = { fields: Field[] }; const schema: Schema = { fields: [ { name: 'id', kind: 'integer', required: true }, { name: 'name', kind: 'string', required: true }, { name: 'debits', kind: 'float' }, ] } // 自动推断出类型:{ id: number; name: string; debits?: number } type Customer = InferFromSchema<typeof schema>; // customer会严格遵循推断出的类型 const customer: Customer = { id: 1, name: 'John Doe', debits: 50 // 这个字段可选,写不写都符合类型要求 }
额外优化:用const断言提升类型精度
如果你的Schema是固定不变的常量,还可以用as const断言让TypeScript推断出更精确的字面量类型,不用依赖Field和Schema类型注解也能正常工作:
const schema = { fields: [ { name: 'id', kind: 'integer', required: true }, { name: 'name', kind: 'string', required: true }, { name: 'debits', kind: 'float' }, ] as const } as const; // 调整工具类型适配常量场景 type InferFromConstSchema<S extends { fields: readonly any[] }> = { [F in S['fields'][number] as F['name']]: F extends { kind: infer K } ? K extends 'string' ? string : K extends 'integer' | 'float' ? number : K extends 'bool' ? boolean : never : never } & { [F in S['fields'][number] as F['name']]?: F extends { required: true } ? never : F extends { kind: infer K } ? K extends 'string' ? string : K extends 'integer' | 'float' ? number : K extends 'bool' ? boolean : never : never } extends infer O ? { [K in keyof O as O[K] extends never ? never : K]: O[K] } : never; type Customer = InferFromConstSchema<typeof schema>;
这种方式下,TypeScript会精确识别每个字段的字面量值,推断出的类型会更严谨。
备注:内容来源于stack exchange,提问作者Belizário Ribeiro
相关产品推荐
相关产品推荐

