启用noUncheckedIndexedAccess时TS报错2722的原因与解决方法
编辑说明:已采纳的回答并非解决方案,可查看对应解决方案。
未启用编译选项时的正常代码
以下是未启用noUncheckedIndexedAccess时可正常运行的代码:
type A = { [key: string]: () => 123 } function fun3<T extends A>(arg: T) { return (key: keyof T) => arg[key](); // 无报错,因为未启用noUncheckedIndexedAccess } console.log(fun3({ hello: () => 123, holle: () => 123 })('hello')); // [123, 123]
启用noUncheckedIndexedAccess后的报错情况
启用noUncheckedIndexedAccess编译选项后,相同代码会触发报错:
type A = { [key: string]: () => 123 } function fun3<T extends A>(arg: T) { return (key: keyof T) => arg[key](); // 报错,因为已启用noUncheckedIndexedAccess } console.log(fun3({ hello: () => 123, holle: () => 123 })('hello')); // [123, 123]
报错信息:
Cannot invoke an object which is possibly 'undefined'.(2722)
我无法理解为什么会出现这个报错:在我看来,key显然是arg的键,因此arg[key]肯定不是undefined。
能否有人解释原因并给出解决办法?(关闭noUncheckedIndexedAccess并非可行选项)
我尝试添加noPropertyAccessFromIndexSignature等其他选项,但并未解决问题。
原因解释
启用noUncheckedIndexedAccess后,TypeScript会对所有索引访问强制添加undefined的可能性,哪怕是通过keyof T获取的键。这是因为T extends A的约束并没有限制T的属性必须是必选的——如果有人传入一个带有可选属性的对象(比如{ hello?: () => 123 }),那么keyof T依然会包含hello,但arg[key]就可能是undefined。TypeScript在泛型层面无法自动推断出T的所有属性都是非可选的,因此会触发这个报错。
解决办法
方案1:约束T的所有属性为必选
修改泛型约束,确保T的每个属性都是非可选的() => 123类型:
type A = { [key: string]: () => 123 } function fun3<T extends { [K in keyof T]: () => 123 }>(arg: T) { return (key: keyof T) => arg[key](); }
通过{ [K in keyof T]: () => 123 }的约束,排除了T包含可选属性的可能,TypeScript就能确定arg[key]不会是undefined。
方案2:使用非空断言
如果能确保传入的arg没有可选属性,可以用非空断言操作符!明确告诉TypeScriptarg[key]不会为undefined:
type A = { [key: string]: () => 123 } function fun3<T extends A>(arg: T) { return (key: keyof T) => arg[key]!(); }
这种方式简单直接,但需要开发者自行保证运行时不会出现undefined的情况。
方案3:类型断言
也可以通过类型断言直接指定arg[key]的类型:
type A = { [key: string]: () => 123 } function fun3<T extends A>(arg: T) { return (key: keyof T) => (arg[key] as () => 123)(); }
和非空断言类似,这种方式同样需要开发者确保代码的安全性,避免传入带有可选属性的对象导致运行时错误。
内容的提问来源于Stack Exchange,提问作者Page not found

