TypeScript中检测null的基础类型守卫失效问题排查
问题描述
我编写了名为isLegacyPayment的类型守卫,当判断出payment是遗留支付(stripeId为null)时抛出错误,但后续代码中TypeScript仍判定payment.stripeId可能为null。不想使用反向守卫isNotLegacyPayment,因为这个命名容易引发开发者混淆,希望修复isLegacyPayment使其正常工作。
报错信息
Type 'string | null' is not assignable to type 'string'. Type 'null' is not assignable to type 'string'.(2322)
原始代码
type Payment = { stripeId: null | string; } function isLegacyPayment<T extends Pick<Payment, 'stripeId'>>(payment: T): payment is T & { stripeId: null } { return payment.stripeId === null; } function test() { const payment: Payment = { stripeId: '12321' }; if (isLegacyPayment(payment)) { throw new Error('Is legacy payment'); } const stripeId: string = payment.stripeId; // 此处出现类型错误 }
解决方案
问题根源在于类型守卫的泛型定义没有让TypeScript正确识别:当守卫返回true并抛出错误后,剩余代码中的payment类型应该被缩小为stripeId必为string的版本。
方案一:简化类型守卫定义
直接去掉泛型,明确守卫的判断类型:
function isLegacyPayment(payment: Payment): payment is { stripeId: null } { return payment.stripeId === null; }
方案二:保留泛型并调整约束
如果需要支持Payment的子类型,修改泛型约束为直接继承Payment:
function isLegacyPayment<T extends Payment>(payment: T): payment is T & { stripeId: null } { return payment.stripeId === null; }
修改后,TypeScript会正确推断:当isLegacyPayment(payment)为true并抛出错误时,后续代码中的payment.stripeId必然是string类型,不会再出现类型错误。
内容的提问来源于stack exchange,提问作者Noitidart
相关产品推荐
相关产品推荐

