TypeScript泛型问题:为对象指定类型时保留类型推断能力
TypeScript泛型默认参数的类型推断问题解决方案
问题背景
使用带默认泛型参数的Model类型时,若直接用Model标注变量,会丢失属性的精确类型信息,导致传入create函数后无法识别具体属性键;只有手动给Model传入泛型参数,或直接在create中传入字面量,才能保留类型推断优势。
给定类型定义:
type Attributes = Record<string, any>; type Model<TAttributes extends Attributes = Attributes> = { attributes: TAttributes; }; function create<TModels extends Record<string, Model>>( schemas: TModels ): TModels { return schemas; }
问题示例:
// 手动传泛型,类型精确 const TodoWithGeneric: Model<{ name: string; finished: boolean }> = { attributes: { name: "string", finished: false } }; // 直接用Model标注,attributes退化为Record<string, any> const TodoWithoutGeneric: Model = { attributes: { name: "string", finished: false } }; const withInference = create({ Todo: { attributes: { name: "string", finished: false } } }); const withGenericsPassed = create({ Todo: TodoWithGeneric }); const withoutAttributesPassedToGeneric = create({ Todo: TodoWithoutGeneric }); // withInference和withGenericsPassed的Todo.attributes能识别属性键 // withoutAttributesPassedToGeneric的Todo.attributes无法识别具体属性
解决方案:用身份函数自动推导精确类型
创建一个asModel身份函数,自动推导传入对象的attributes类型,既保证变量符合Model结构,又保留精确的属性类型信息:
type Attributes = Record<string, any>; type Model<TAttributes extends Attributes = Attributes> = { attributes: TAttributes; }; // 自动推导TAttributes的身份函数 function asModel<T extends Attributes>(model: Model<T>): Model<T> { return model; } function create<TModels extends Record<string, Model>>(schemas: TModels): TModels { return schemas; }
使用方式
// 无需手动传泛型,自动推导attributes的具体类型,同时做结构检查 const TodoWithoutGeneric = asModel({ attributes: { name: "string", finished: false } }); const withAutoInference = create({ Todo: TodoWithoutGeneric }); // 此时withAutoInference.Todo.attributes可正确识别name、finished的类型和键名
方案说明
asModel函数会让TypeScript自动推导T为传入的attributes的具体类型,返回的是精确的Model<T>,而非默认的Model<Attributes>。- 声明变量时,既得到
Model的结构校验(比如缺少attributes会报错),又无需手动传入泛型参数;传入create函数时,精确的类型信息得以保留,实现类型推断的预期效果。
内容的提问来源于stack exchange,提问作者Arthur
相关产品推荐
相关产品推荐

