TypeScript中能否从只读对象常量列表推导/推断出联合类型?
TypeScript中能否从只读对象常量列表推导/推断出联合类型?
当然可以实现!你遇到的问题主要是两个核心点:一是初始的Obj类型抹掉了name属性的字面量类型信息,二是原生Array.map的类型定义无法保留元组的字面量细节。下面分两种场景一步步解决你的需求:
一、手动收集对象name属性的场景(你的第一个示例)
首先,问题出在你定义的Obj类型里,name被声明为宽泛的string类型,导致即使你给x/y/z赋值了字面量字符串,TypeScript也会把它们的name类型收窄为string,而不是具体的'x'/'y'/'z'。
我们可以用satisfies操作符来兼顾类型约束和字面量类型保留:
// 保留原有的Obj类型约束 type Obj = Readonly<{ name: string }>; // 使用as const + satisfies,既确保符合Obj类型,又让TypeScript推断出字面量类型 const x = { name: 'x' } as const satisfies Obj; const y = { name: 'y' } as const satisfies Obj; const z = { name: 'z' } as const satisfies Obj; // 现在objNames的类型会被推断为readonly ['x', 'y', 'z'] const objNames = [x.name, y.name, z.name] as const; // 自然就能得到联合类型 'x' | 'y' | 'z' type objNamesT = typeof objNames[number];
二、通过对象列表推导的场景(你的第二个示例)
这个场景里,我们可以分类型层面提取联合类型和运行时保留字面量数组类型两个部分处理:
1. 类型层面直接提取联合类型
不需要依赖运行时的map操作,直接从objList的类型中提取name的联合类型即可:
// 先确保objList是只读元组,保留每个对象的字面量类型 const objList = [x, y, z] as const; // 直接通过索引访问提取联合类型,结果就是'x' | 'y' | 'z' type objNamesT2 = typeof objList[number]['name'];
2. 运行时得到带字面量类型的name数组
原生的Array.map会把元组转为普通数组,并且丢失字面量类型。我们可以自定义一个类型安全的映射函数来保留元组的字面量信息:
// 自定义一个类型安全的map函数,专门提取name属性 function extractNames<T extends readonly Obj[]>(arr: T): { [K in keyof T]: T[K]['name'] } { return arr.map(obj => obj.name) as any; } // 调用后objNames2的类型会被推断为readonly ['x', 'y', 'z'] const objNames2 = extractNames(objList);
这样不管是类型层面还是运行时层面,都能精准得到你想要的字面量联合类型和字面量数组类型啦!
备注:内容来源于stack exchange,提问作者JWB
相关产品推荐
相关产品推荐

