TypeScript如何编写支持任意自定义键的泛型数据类型
TypeScript 中接口的索引签名返回值类型,必须兼容接口内所有明确声明的属性类型。你当前定义的[key:string]:string要求所有字符串键对应的值必须是string类型,但同时又声明了age:number,number类型不兼容string,直接触发类型冲突。另外这种固定索引值类型的写法,也无法适配不同对象持有不同自定义键、自定义键值类型不统一的场景。
根据你对类型精度的不同要求,可以选以下几种写法:
方案1:固定自定义键值类型,快速适配简单场景
如果你的所有自定义键的值都是字符串,仅age为数值,直接把索引签名的返回值改成兼容两种类型的联合类型即可:interface Dic { [key: string]: string | number; age: number; } const Object1: Dic = { name: "name1", age: 0 } const Object2: Dic = { village: "name1", age: 40 }这个写法可以通过类型校验,但缺点是类型精度低:所有自定义键的值都会被拓宽为
string | number,TS无法识别Object1.name一定是字符串类型,也不会校验你传入的值类型是否和自定义键的预期匹配。方案2:保留对象精确类型,强制结构校验
如果你希望既校验对象必须包含number类型的age属性,又能保留每个对象自定义键的精确类型提示,可以用泛型搭配satisfies运算符实现(TS 4.9及以上版本支持):type Dic<T extends Record<string, unknown>> = T & { age: number; } const Object1 = { name: "name1", age: 0 } satisfies Dic<{ name: string }>; const Object2 = { village: "name1", age: 40 } satisfies Dic<{ village: string }>;这种写法下,TS会自动推导每个对象的完整结构:访问
Object1.name时能识别到是string类型,访问不存在的属性、或者age传非数字值都会直接抛类型错误。方案3:高兼容性灵活写法,自动推导类型
如果你的自定义键值类型也不固定,或者使用的TS版本较低不支持satisfies,可以通过泛型函数做自动推导:function createDic<T extends { age: number }>(obj: T) { return obj; } const Object1 = createDic({ name: "name1", age: 0, isActive: true // 支持任意类型的自定义属性 }); const Object2 = createDic({ village: "name1", age: 40, population: 1200 });这个方案不需要提前声明每个对象的自定义键结构,只要传入的对象包含
number类型的age属性就能通过校验,同时会完整保留每个对象的属性类型,使用时不会丢失类型提示,适配性最强。
内容的提问来源于stack exchange,提问作者user2024080

