TypeScript:如何提取Model泛型属性内部类型并保留其他属性?
问题原因与解决方案
核心原因
你的代码出现普通属性类型被推断为unknown的问题,大概率是因为Model类型的泛型参数设置了默认值unknown(比如定义为type Model<T = unknown> = { /* ... */ })。
当TypeScript执行T[P] extends Model<infer R>的条件判断时,如果Model有默认泛型参数,它会自动将默认值unknown填充进去,尝试判断普通类型(比如number、string)是否能匹配Model<unknown>。如果Model的结构允许这种宽松匹配(比如包含可选属性、或者是兼容基础类型的联合类型),就会触发条件分支,导致infer R被推断为unknown,最终普通属性的类型被替换成unknown。
解决方案
根据Model的定义场景,有三种常见的解决方式:
方式1:移除Model的泛型默认参数
如果Model不需要默认类型参数,直接去掉默认值,强制必须传入具体类型:
// 修正Model的定义,去掉默认参数 type Model<T> = { data: T }; type MyType<T> = { [P in keyof T]: T[P] extends Model<infer R> ? R : T[P]; }; // 测试示例 type Test = MyType<{ name: string; age: Model<number> }>; // 结果:{ name: string; age: number }
方式2:给Model添加唯一标识,严格区分类型
如果必须保留Model的泛型默认参数,可以给Model添加一个唯一的标识属性,确保只有真正的Model实例才会被匹配:
// 添加__isModel标识属性 type Model<T = unknown> = { __isModel: true; data: T }; type MyType<T> = { [P in keyof T]: T[P] extends { __isModel: true; data: infer R } ? R : T[P]; }; // 测试示例 type Test = MyType<{ name: string; age: Model<number> }>; // 结果:{ name: string; age: number }
方式3:双重条件判断,避免宽松匹配
如果不想修改Model的定义,可以通过双重条件判断确保精确匹配:
type Model<T = unknown> = { data: T }; type MyType<T> = { [P in keyof T]: T[P] extends Model<infer R> ? (Model<R> extends T[P] ? R : T[P]) : T[P]; }; // 测试示例 type Test = MyType<{ name: string; age: Model<number> }>; // 结果:{ name: string; age: number }
这里的双重判断会先验证T[P]是否能赋值给Model<infer R>,再反向验证Model<R>是否能赋值给T[P],排除因默认参数导致的宽松匹配情况。
内容的提问来源于stack exchange,提问作者jlang
相关产品推荐
相关产品推荐

