TypeScript中Promise catch与try/catch的类型检查差异疑问
关于TypeScript中Promise链式调用与try/catch的类型检查差异
问题描述
我认为以下代码不应正常运行:insertObj函数声明返回Promise<MyObject>,但当catch分支执行时实际会返回null。为何该写法在我的代码及TypeScript REPL中都不报错?
class MyObject { myField = '' } type z = typeof MyObject; type Persister<T> = { create:(a: any) => T; save: (a: MyObject) => Promise<MyObject> } type DataSource = { getRepository: (obj: typeof MyObject) => Persister<MyObject> } let dataSource: DataSource; async function insertObj(name: string): Promise<MyObject> { const appRepo = dataSource.getRepository(MyObject); let obj: (MyObject | null) = appRepo.create({ name }); await appRepo.save(obj) .then(res => { obj = res; }) .catch(() => { obj = null; }); return obj; }
另外,若将代码修改为以下try/catch形式,return语句会触发“不可赋值”异常,我认为两种形式等价,请问我忽略了什么?
async function insertObj(name: string): Promise<MyObject> { const appRepo = dataSource.getRepository(MyObject); let obj: (MyObject | null) = appRepo.create({ name }); try { obj = await appRepo.save(obj); } catch(err) { obj = null; } return obj; }
解答
1. then/catch写法不报错的原因
TypeScript的控制流分析不会跨函数作用域追踪变量的类型变化。在链式调用的then和catch回调里,你对obj的赋值操作属于回调函数内部的逻辑,TypeScript无法将这些回调里的类型修改同步到外部的obj变量上。
在return obj的位置,TypeScript只能看到obj的初始类型是MyObject | null,但它无法识别到catch分支会把obj设为null——因为回调函数的执行逻辑被视为独立于主函数的控制流,所以TypeScript没有触发类型不匹配的错误。但实际上运行时,如果进入catch分支,函数确实会返回null,这属于TypeScript类型检查的一个局限性。
2. try/catch写法报错的原因
try/catch是同一函数作用域内的控制流结构,TypeScript可以完整追踪这个作用域内的变量类型变化:
- 如果
try块执行成功,obj会被赋值为MyObject类型; - 如果进入
catch块,obj会被赋值为null。
所以在return obj时,TypeScript能准确判断出obj的类型是MyObject | null,而函数声明的返回类型是Promise<MyObject>(不允许null),因此触发类型错误,这才是符合预期的严格类型检查行为。
内容的提问来源于stack exchange,提问作者UndefinedBehavior
相关产品推荐
相关产品推荐

