TypeScript中如何通过keyof获取接口指定类型的键?
问题:如何从TypeScript接口中仅提取指定类型字段的键?
首先看简化后的接口和示例对象:
interface Person { name: string; address: string; age: number; height: number; } const person: Person = { name: 'Yair', address: 'here', age: 12, height: 186 };
需求是创建函数动态更新name/address这类字符串类型字段,直接指定联合类型"name"|"address"可以正常运行:
let updateNameOrAddress = (key: "name"|"address", value: string): void => { person[key] = value; };
但随着字符串类型字段增多,这种写法会非常繁琐。尝试用keyof Person替代时出现类型错误:
let updateNameOrAddress = (key: keyof Person, value: string): void => { person[key] = value; // 错误:Type 'string' is not assignable to type 'never' };
错误原因是keyof Person包含了age/height这类数字类型的键,TypeScript无法保证string类型的value能匹配所有可能的字段类型,因此抛出报错。
解决方案
可以通过TypeScript的条件类型定义工具类型,精准筛选出接口中字段类型为指定类型的键。
1. 定义工具类型提取目标键
// 提取接口中字段类型为string的键 type StringKeys<T> = { [K in keyof T]: T[K] extends string ? K : never; }[keyof T]; // 同理,提取数字类型字段的键可写为: // type NumberKeys<T> = { [K in keyof T]: T[K] extends number ? K : never }[keyof T];
2. 基于工具类型编写更新函数
用StringKeys<Person>作为key的类型,自动筛选出name/address,同时保证value类型匹配:
let updateNameOrAddress = (key: StringKeys<Person>, value: string): void => { person[key] = value; // 类型检查通过,无报错 }; // 测试示例: updateNameOrAddress('name', 'NewName'); // 合法 updateNameOrAddress('address', 'NewAddress'); // 合法 // updateNameOrAddress('age', 20); // 报错:"age"不属于合法key范围
3. 通用化更新函数(可选)
如果需要支持任意字段的类型安全更新,可以写一个泛型函数,自动根据key推断value类型:
function updateField<T, K extends keyof T>(obj: T, key: K, value: T[K]): void { obj[key] = value; } // 调用示例: updateField(person, 'name', 'Yair Updated'); // 合法 updateField(person, 'age', 13); // 合法 // updateField(person, 'name', 123); // 报错:number类型无法赋值给string字段
内容的提问来源于stack exchange,提问作者GuruYaya
相关产品推荐
相关产品推荐

