前面讲类型断言时,提到可以通过断言 as 将联合类型断言为某一具体类型进而访问其存在的属性,但这样每次访问都需要进行断言且有风险:

  1. function getCount(data: any[] | Set<any>): Number {
  2. if (Object.prototype.toString.call(data) === "[object Array]") {
  3. // ERROR: 类型“any[] | Set<any>”上不存在属性“length”。类型“Set<any>”上不存在属性“length”
  4. return data.length;
  5. }
  6. // ERROR: 类型“any[] | Set<any>”上不存在属性“size”。类型“any[]”上不存在属性“size”
  7. return data.size;
  8. }

使用断言解决

  1. function getCount(data: any[] | Set<any>): Number {
  2. if (Object.prototype.toString.call(data) === "[object Array]") {
  3. return (data as Array<any>).length;
  4. }
  5. return (data as Set<any>).size;
  6. }

使用条件判断

in instanceof Array.isArray 等判断条件,为真后自然能访问其属性:

  1. function getCount(data: any[] | Set<any>): Number {
  2. if ('length' in data) {
  3. return data.length;
  4. }
  5. return data.size;
  6. }

使用类型谓词 is

一般用于函数返回值类型中,判断参数是否属于某一类型,并根据结果返回对应的布尔类型。它不仅返回函数运行结果到判断条件中,还返回结果类型到条件块中。

  1. function isArray(u: any): u is Array<any> {
  2. return Object.prototype.toString.call(u) === "[object Array]";
  3. }
  4. function getCount(data: any[] | Set<any>): Number {
  5. if (isArray(data)) {
  6. return data.length;
  7. }
  8. return data.size;
  9. }

你可能会发现前面使用断言或条件判断还比使用类型谓词 is 更加简单(少些一个函数),但当要判断的联合类型不止两个子类型时,类型谓词 is 的优势就出现了:

  • 比断言更安全
  • 不用每处都编写特定的条件判断,可用泛型函数解决: