如何编写仅允许更新对象类型值的TypeScript泛型函数?
解决方案
首先,你需要定义一个类型工具,用来提取对象中值为object类型的键(排除null,因为typeof null会返回object):
type ObjectKeys<T> = { [K in keyof T]: T[K] extends object ? K : never; }[keyof T];
这个类型会遍历目标对象的所有键,只保留对应值为object类型的键,其他键会被映射为never,最终通过索引访问得到合法键的集合。
接下来修改你的updateDbItem函数,把泛型K的约束从keyof SItem改为ObjectKeys<SItem>,这样函数就只接受值为object类型的键:
enum SKey { key1 = "key1", key2 = "key2", } type SItem = { [SKey.key1]: boolean; [SKey.key2]: { attr1: string; attr2: boolean; }; }; const mapDB: SItem = { [SKey.key1]: true, [SKey.key2]: { attr1: "hello", attr2: true, }, }; // 过滤出值为object类型的键 type ObjectKeys<T> = { [K in keyof T]: T[K] extends object ? K : never; }[keyof T]; export function updateDbItem<K extends ObjectKeys<SItem>>( key: K, newFields: Partial<SItem[K]> ) { const item = mapDB[key]; mapDB[key] = { ...item, ...newFields }; // 此时TS能确定item是object类型,不会报错 }
效果验证
- 调用合法键(key2):正常通过类型检查
updateDbItem(SKey.key2, { attr1: "world" }); // ✅ 合法 - 调用非法键(key1):直接触发类型错误,符合预期
updateDbItem(SKey.key1, {}); // ❌ 类型错误:类型"SKey.key1"不能赋值给类型"SKey.key2"
错误原因说明
你之前遇到的TS2698错误,是因为原函数的泛型K允许所有keyof SItem,包括对应值为boolean的key1。TS无法保证mapDB[key]一定是object类型,因此不允许使用对象展开语法。通过ObjectKeys约束K后,TS能明确知道SItem[K]必然是object类型,展开操作就合法了。
内容的提问来源于stack exchange,提问作者Thomas Gak-Deluen
相关产品推荐
相关产品推荐

