TypeScript严格模式下,如何检查表达式作为对象属性名的undefined?
TypeScript 表达式属性访问时的类型收窄问题解决方法
报错代码示例
type Props = 'foo' | 'bar'; type ParRec = Partial<Record<Props, string>>; function doSomething (item: ParRec) { const props: Props[] = ['foo', 'bar']; return props.map((prop) => { if(item[prop]) { const result: string = item[prop]; // 此处抛出ts(2322)错误 return { result }; } return {}; }); }
TypeScript在此处抛出**ts(2322)**错误,提示string | undefined 不能赋值给类型 string。尽管通过if(item[prop])做了非空判断,但由于使用表达式作为属性名,TypeScript无法正确收窄类型。
无报错代码对比
function doSomething (item: ParRec) { const props: Props[] = ['foo', 'bar']; return props.map((prop) => { if(item.foo) { // 使用item['foo']也可正常运行 const result: string = item.foo; return { result }; } return {}; }); }
直接使用明确的属性名(无论点语法还是字符串字面量索引)时,TypeScript能正确识别条件判断后的类型,不会报错。
严格模式下的解决方法
以下方法适用于TypeScript 4.8.4严格模式:
暂存属性值到局部变量
将item[prop]先存入局部变量,TypeScript会跟踪该变量的类型,条件判断后自动收窄:function doSomething (item: ParRec) { const props: Props[] = ['foo', 'bar']; return props.map((prop) => { const val = item[prop]; if(val) { const result: string = val; return { result }; } return {}; }); }使用非空断言
通过!断言值不为undefined,注意需确保逻辑上该值确实不会为undefined,避免运行时错误:function doSomething (item: ParRec) { const props: Props[] = ['foo', 'bar']; return props.map((prop) => { if(item[prop]) { const result: string = item[prop]!; return { result }; } return {}; }); }自定义类型守卫函数
编写类型守卫来明确告知TypeScript,当条件满足时属性值已定义:function hasDefinedProp<T, K extends keyof T>(obj: T, key: K): obj is T & { [P in K]-?: T[P] } { return obj[key] !== undefined; } function doSomething (item: ParRec) { const props: Props[] = ['foo', 'bar']; return props.map((prop) => { if(hasDefinedProp(item, prop)) { const result: string = item[prop]; return { result }; } return {}; }); }空值合并兜底
使用??为可能的undefined值提供默认值,确保类型始终为string:function doSomething (item: ParRec) { const props: Props[] = ['foo', 'bar']; return props.map((prop) => { const result = item[prop] ?? ''; if(result) { return { result }; } return {}; }); }
内容的提问来源于stack exchange,提问作者Neil S
相关产品推荐
相关产品推荐

