Day17: 【TypeScript 学起来】什麽是 Narrowing?

其实看官网看这篇的时候很想pass,有点看不下去XD,但还是做了笔记。若有错误,欢迎留言指教,感恩的心。

Narrowing

Narrowing 指的是将某一个可能是多种型别的变数,缩小成具体型别的过程,通常用在联合型别。他的好处就是,有点像检查你什麽型别的时候就做什麽事,分工明确,常出现在 if... else 里使用。

有点抽象,来用code理解吧:

❌ 依照下面 padLeft 函式,他想要做的功能是当 padding 参数是数字的时候,就会依据该数字在input前加上多少个空格,若当padding是字串时,就在input前加入该字串。 但以下例子, 当 padding 参数带入数字时,会报错。

function padLeft(padding: number | string, input: string) {
  return new Array(padding + 1).join(" ") + input;
}

//error: Operator '+' cannot be applied to types 'string | number' and 'number'.

✅ 所以我们应该要先检查 padding 型别是不是 number,再依不同型别去各自做处理,下面这个例子是以 typeof 去 narrow 不同型别的执行范围,这个过程就是 narrowing。 其实我前面文章也有用过相关的方法,才知道原来在 TypeScript 有 narrowing 概念之说。

function padLeft(padding: number | string, input: string) {
  if (typeof padding === "number") { //数字
    return new Array(padding + 1).join(" ") + input; 
  }
  return padding + input; //其他就是字串
}

使用typeof type guards

typeof 的操作可以让我们取得值的型别类型,如string,number,boolean,symbol,undefined,object,function。 但 null 除外。

如下例子,typeof strs === "object" 这就是一种 type guards (型别保护)。虽然 null 无法使用 typeof 来取得型别,但 null 也是object, TypeScript 会提醒 strs 有可能是 null。 (tsconfig 记得打开严谨模式)

function printAll(strs: string | string[] | null) {
    if (typeof strs === "object") {
      for (const s of strs) {
       //Object is possibly 'null'.
      }
    } else if (typeof strs === "string") {
      console.log(strs);
    } else {
      console.log(strs);
    }
}

Equality narrowing

可以使用 switch 或是 ===!====, and != 来缩小型别。

function printAll(strs: string | string[] | null) {
  if (strs !== null) {
    if (typeof strs === "object") {
      for (const s of strs) {
        console.log(s);
      }
    } else if (typeof strs === "string") {
      console.log(strs);
    }
  }
}

使用"value" in x

使用"value" in x的概念, value 为 string literal,x 为联合型别(animal)。

type Fish = { swim: () => void };
type Bird = { fly: () => void };
 
function move(animal: Fish | Bird) {
  if ("swim" in animal) {  //animal 物件里有属性 "swim",则一定是 Fish 型别
    return animal.swim();
  }
 
  return animal.fly();
}

使用 instanceof

instanceof 用来检查某个值是否为某个 constructor。如下面例子, 如果 x参数为 Date constructor, 就可以进行toUTCString()的方法。其他就是字串,就进行toUpperCase()方法。

function logValue(x: Date | string) {
  if (x instanceof Date) { 
    console.log(x.toUTCString());       
    //(parameter) x: Date 
  } else {
    console.log(x.toUpperCase());
    //(parameter) x: string
  }
}

使用 Assignments

我们进行赋值时给予限制也进行了 narrowing。如下方例子,在赋予 x 值时, x 的型别就会是 number 或者 string。 我们赋值数字或字串都是ok的, 但赋值boolean就会报错提醒。

let x = Math.random() < 0.5 ? 10 : "hello world!";
console.log(Math.random());
console.log(x);
x = 1; 
console.log(x); //1
x = true;  //error:Type 'boolean' is not assignable to type 'string | number'.


下篇继续讲 narrowing 唷,觉得难,我觉得啦QQ,明天见!


参考资料

https://www.typescriptlang.org/docs/handbook/2/narrowing.html


<<:  Day17 Android - Array、ArrayList、List

>>:  【Day 20】Algorithm - Practice 2

追求JS小姊姊系列 Day14 -- 方函式的能力展现:认识生成器,工具人更神气(上)

前情提要 方函式准备展示第二个型态 我:有些情境下,时间就是不能掌握,这要求也太夸张了。 方函式:很...

Day 9 整理重复烦人的程序码!

该文章同步发布於:我的部落格 昨天我们实作了把 example 给拆开,并且让整个测试更具备逻辑。...

[Day25] 找回密码API – views

哈罗大家好,今天要来撰写我们找回密码API的逻辑,先来看看我的程序码吧~~ 程序码 from dat...

第 12 天 小有成果保持练习( leetcode 043 )

https://leetcode.com/problems/multiply-strings/ M...

[Day 8]从零开始学习 JS 的连续-30 Days---阵列

宣告变数的资料型别--阵列 1.数值( Number ) 2.字串( String ) 3.布林值(...