聊一聊 TypeScript Type Guard (类型保护)

2,104 阅读2分钟

前段时间在专心工(摸)作(🐟)的时候,在交流群看到了一个群友的求助:如何让下图中这段代码不报错

使用 as 并不能解决问题,as 只对编译期类型校验有效且只是临时收窄变量的类型。而且这里出现了 if 条件判断,这样并不会收窄 data 的类型,在分支里面,data 的类型 还是 Tdata

使用 as 的场景应该是你十分确定数据的类型时才可以使用。

比如下面这段代码,但这种代码十分的不优雅。

if(hasCode(data)) {
	console.log((data as Ia).code);
}

我给出的答案是

interface IA {
  name: string;
  code: number;
}

interface IB {
  name: string;
  age: string;
}

type IC = IA | IB;

function test(data: IC) {
  if ("code" in data) {
    console.log(data.code); // data: IA
  } else {
    console.log(data.age);  // data: IB
  }
}

但是有同学指出,使用in运算符会往原型链上面找

OK fine,我只能祭出了终极武器:自定义类型守卫(User-Defined Type Guards

function isIA(data: any): data is IA {
  return typeof data.code !== "undefined";
}

function test(data: IC) {
  if (isIA(data)) {
    console.log(data.code); // data: IA
  } else {
    console.log(data.age);  // data: IB
  }
}

内置 Type Guard

typescript 类型判断有以下三种,分别适用于不同场景

  • typeof,适用于判断基本类型
  • instanceof,适用于判断类
  • in,适用于判断对象

这几个都是属于 js 的运算符,运行时也会起作用,不单单是编译期进行类型判断

自定义 Type Guard

很多人可能也写过这种代码:

if(typeof val === 'string') {
	val.split(''); // ok
}
function isStr(val: any) {
	return typeof val === 'string';
}

if(isStr(val)) {
	val.split(''); // Property 'split' does not exist
}

有没有觉得很奇怪,只是把一段代码封装成函数,typescript 就不认识了(没得办法,typescript还没那么智能到可以知道你函数里做了什么)

function isIA(data: any): data is IA {
  return typeof data.code !== "undefined";
}

解决办法就是使用上面那段代码,使用自定义Type Guard 使用方法如下段代码:在声明函数返回值类型的地方写 val is TypeType 是你要判断的类型

function myTypeGuard(val: any): val is Type;

参考