TypeScript:如何强制泛型函数从obj参数推断泛型类型?
强制泛型T从obj参数推断的解决方案
当然可以解决这个问题!核心思路是调整泛型的推断逻辑,让T严格从传入的obj参数中提取类型,而不是被create函数的返回类型“带偏”。
修改后的实现代码
我们可以通过直接约束泛型参数,从obj的类型中提取值类型,强制create的返回类型与obj的存储类型匹配:
function getOrPut<T extends Record<string, any>>( obj: T, key: string, create: () => NonNullable<T[string]> ): NonNullable<T[string]> { const value = obj[key]; // 用严格的undefined判断,避免0、空字符串等 falsy 值被误判为不存在 if (value !== undefined) { return value; } else { return obj[key] = create(); } }; type Item = { title: string }; type Dictionary = { [key: string]: Item }; const dictionary: Dictionary = {}; // 现在这行代码会直接报错:类型"{}"缺少类型"Item"中的属性"title",符合预期! // const foo = getOrPut(dictionary, 'foo', () => ({})); // 正确调用示例 const bar = getOrPut(dictionary, 'bar', () => ({ title: 'Hello World' })); // bar 的类型是 Item,完全符合预期
原理说明
- 泛型参数调整:我们将泛型参数改为
T extends Record<string, any>,让T直接代表传入的obj的完整类型,而不是原来的“值类型”。 - 提取目标值类型:通过
NonNullable<T[string]>,从obj的类型中提取出它的索引值类型,并排除undefined(避免类型污染)。 - 强制类型匹配:
create函数的返回类型被约束为NonNullable<T[string]>,也就是必须和obj中存储的类型完全兼容,彻底杜绝了create返回类型覆盖obj类型的问题。
额外优化点
原来的if (value)判断存在漏洞:如果obj中存储的是0、''这类 falsy 值,会被误判为“不存在”。改成value !== undefined后,判断逻辑更严谨,只针对“未定义”的场景处理。
内容的提问来源于stack exchange,提问作者Valeriy Katkov
相关产品推荐
相关产品推荐

