如何使用TypeScript泛型推断对象属性的具体类型
场景1:简化示例问题解决方案
原代码中names的类型被宽泛推断为string | number,是因为People的索引签名抹平了具体的字面量类型,同时数组默认会被推断为宽泛的数组类型而非字面量元组。要实现自动推断具体的联合类型,按以下步骤修改:
修正代码
// 移除原有的People类型约束,使用as const保留数组的字面量类型 const people = { bert: { names: ["Bert", 1] as const, }, ernie: { names: ["Ernie", 2, "The Ern"] as const, }, }; // 泛型函数捕获传入对象的具体类型 function getNames<T extends { names: readonly any[] }>(person: T): T['names'][number] { // 示例逻辑:返回第一个元素,实际可按需修改 return person.names[0]; } const names = getNames(people.bert); // 类型自动推断为 "Bert" | 1
关键要点
- 保留字面量类型:用
as const标记数组,让TypeScript将其识别为只读元组,而非宽泛的(string | number)[]。 - 泛型捕获具体类型:泛型参数
T会自动捕获传入person的具体结构,通过T['names'][number]提取元组元素的联合类型。
场景2:实际业务场景解决方案
要让variant自动推断为"variant1" | "variant2",核心是保留variants数组的字面量类型,并通过泛型函数传递类型信息:
修正代码
// 用as const标记整个对象,确保所有键和数组元素都保留字面量类型 const tests = { test1: { variants: ["variant1", "variant2"] as const, }, // 可添加更多测试项 test2: { variants: ["a", "b", "c"] as const, } } as const; // 泛型函数捕获测试项的具体类型,返回变体的联合类型 function getRandomVariant<T extends { variants: readonly string[] }>(test: T) { const randomIndex = Math.floor(Math.random() * test.variants.length); return test.variants[randomIndex] as T['variants'][number]; } const variant = getRandomVariant(tests.test1); // 类型为 "variant1" | "variant2" if(variant === "variant1") { // 此处variant类型被窄化为"variant1" } else if(variant === "variant2") { // 此处variant类型被窄化为"variant2" }
关键要点
- 全局字面量锁定:外层对象添加
as const,确保tests的键(如test1)和内部数组都保持字面量类型,不会被宽泛推断。 - 泛型类型传递:泛型
T捕获传入测试项的结构,T['variants'][number]直接提取变体的联合类型,实现调用时的自动类型推断。
内容的提问来源于stack exchange,提问作者Xriter
相关产品推荐
相关产品推荐

