如何让TypeScript非空类型收窄实现更优雅?
优化TypeScript非null/undefined类型收窄的优雅方案
你希望通过类型守卫实现对非null/undefined变量的公共方法(如toString、constructor等)的安全访问,当前直接用o !== null && o !== undefined无法让TypeScript自动收窄类型,但自定义类型守卫可以解决问题。以下是几种更优雅的优化方案:
核心问题说明
TypeScript对unknown类型的收窄逻辑严格:即使排除了null和undefined,剩余类型仍为unknown,TS无法确认它具备公共对象方法,因此禁止直接访问属性。自定义类型守卫通过显式声明类型范围,填补了TS类型系统与JS运行时行为的差异。
优化方案1:简化自定义类型守卫
将类型定义和守卫函数写得更紧凑清晰:
// 明确覆盖所有非null/undefined且拥有公共对象方法的类型 export type Something = string | number | boolean | symbol | bigint | object; // 简洁箭头函数形式的类型守卫 export const isSomething = (val: unknown): val is Something => val !== null && val !== undefined; function Narrowing(o: unknown) { if (isSomething(o)) { console.log(o.toString(), o.constructor); } }
优化方案2:复用内置类型(可选)
如果想利用TS内置的NonNullable类型,可以结合条件类型明确范围,这种写法适合追求类型复用的场景:
// 从NonNullable<unknown>中筛选出具备公共方法的类型 export type Something = NonNullable<unknown> extends infer T ? T extends string | number | boolean | symbol | bigint | object ? T : never : never; export const isSomething = (val: unknown): val is Something => val !== null && val !== undefined;
优化方案3:直接使用类型断言(不推荐)
如果不想额外定义类型守卫,可在判断后添加类型断言,这种写法更简洁但丢失了类型守卫的“运行时-类型系统”关联,仅适合简单场景:
function NotNarrowing(o: unknown) { if (o !== null && o !== undefined) { const safeObj = o as string | number | boolean | symbol | bigint | object; console.log(safeObj.toString(), safeObj.constructor); } }
内容的提问来源于stack exchange,提问作者noseratio
相关产品推荐
相关产品推荐

