如何不使用instanceof,仅通过类型守卫实现数组类型推断?
如何不使用instanceof,仅通过类型守卫实现数组类型推断?
嘿,我太懂你想换掉代码里instanceof Array、纯靠类型守卫搞定数组类型推断的需求了!其实操作起来很简单,咱们自定义一个类型守卫函数,再配合TypeScript的类型系统,既能保住运行时的类型校验,编译时的类型安全也不会丢。
先看你原来的代码,push方法的类型约束已经做得很到位——通过T extends Array<infer R> ? R : never自动推断数组元素类型,现在只需要把运行时的instanceof替换成自定义类型守卫就行。
首先写一个数组专属的类型守卫函数:
function isArray<T>(value: unknown): value is Array<T> { // 用Array.isArray做运行时判断,比instanceof靠谱多了,比如跨iframe的数组也能正确识别 return Array.isArray(value); }
接着修改你的Container类,把instanceof换成这个类型守卫:
class Container<T> { constructor(public t: T) { } push(o: T extends Array<infer R> ? R : never) { if (isArray(this.t)) { this.t.push(o); } } } const c = new Container([1,2,3]); c.push(4); // 编译时类型完全匹配,运行时也能正常执行
咱们来掰扯清楚细节:
- 这个
isArray就是类型守卫,它在运行时靠Array.isArray判断值是否为数组,同时在类型层面给TypeScript递话:“要是我返回true,那这个值绝对是Array<T>类型”。 - 这么一来,TypeScript会自动在
if代码块里把this.t的类型缩小成数组类型,保证push调用的安全性。 - 而且比起
instanceof Array,Array.isArray的兼容性和可靠性都更强,遇到跨执行上下文的数组也不会掉链子。
另外,编译时的类型安全也没打折扣:要是你创建一个非数组类型的Container,TypeScript会直接在编译阶段给你报错,根本不让你瞎调用push传值:
const c2 = new Container(5); c2.push(6); // 编译报错!因为T是number类型,push的参数类型是never,啥值都传不进去
这样就彻底实现了不用instanceof,仅靠类型守卫完成数组类型推断和校验的需求啦!
备注:内容来源于stack exchange,提问作者user29889977
相关产品推荐
相关产品推荐

