寻求可同时满足两种类型检查需求的TypeScript Record替代定义
寻求可同时满足两种类型检查需求的TypeScript Record替代定义
我太懂你现在的两难了——想用一个类似Record的类型,既要在通过方括号[]访问任意键时,类型提示是string | undefined(毕竟谁也保证不了这个键一定存在),又要在通过Object.entries遍历的时候,遍历到的值类型是确定的string(因为entries只会返回实际存在的键值对,这些值肯定是有效的)。
先复盘下你遇到的具体问题:
- 原生的
Record<string, string>:方括号访问不存在的键时,TS会错误地推断类型为string,不会提示undefined的风险,直接传给要求非undefined的函数(比如你的print_it)不会触发错误,存在隐患。 - 你提到的
PartialRecord(也就是Partial<Record<K, T>>):虽然解决了方括号访问的类型提示问题,但用Object.entries遍历的时候,值的类型会变成string | undefined,明明遍历到的都是实际存在的有效值,却还要额外处理undefined,非常麻烦。
那有没有一个能同时搞定这两个需求的自定义类型呢?当然有!我们可以定义一个结合了“可选键”和“存在键必为有效值”的类型:
type DesiredRecord<T> = { [key: string]: T | undefined; } & { // 确保所有实际存在的属性值都是T,不会是undefined [K in keyof DesiredRecord<T>]: K extends string ? T : never; };
现在来验证两种场景是否完全符合需求:
1. 方括号访问任意键
const testObj: DesiredRecord<string> = { foo: "hello", bar: "world" }; const existingVal = testObj['foo']; // 类型是string | undefined(符合预期,TS无法静态确定你访问的键是否存在) const randomVal = testObj['random-key']; // 类型也是string | undefined(完全满足需求) // 传给print_it会触发类型错误,因为参数要求非undefined print_it(randomVal); // 错误:Argument of type 'string | undefined' is not assignable to parameter of type 'string'
2. Object.entries遍历
for (const [key, val] of Object.entries(testObj)) { print_it(val); // 类型是string(符合预期,entries只会返回实际存在的键值对,值肯定是string) }
这个类型的核心逻辑很清晰:
- 第一层的
[key: string]: T | undefined告诉TS,任意string键对应的类型可能是T或undefined,完美解决了方括号访问的类型提示问题。 - 第二层的交叉类型确保了所有实际存在的属性的值都是
T,让TS在遍历Object.entries时能正确推断值的类型为T,不会带上不必要的undefined。
这样就不用在代码里额外加类型断言或者处理无意义的undefined分支,完全匹配你提出的两个需求。
内容来源于stack exchange
相关产品推荐
相关产品推荐

