深入 TypeScript-1

Pandaaa發表於2018-11-08

寫在最前面

  • 最近學習 ts,公司中大佬做了一次關於 ts 的分享,收穫頗豐,自己總結了一下筆記,下面給大家分享一下。
  • 第一篇主要是分享幾個關於 ts 型別的幾個細節的問題。

ts 型別

  • 基本型別
    • boolean、number、string、symbol、object、null、undefined
    • enum
    • array、tuple
    • any、void、never、unknown

思考問題?

  • 1、Object 和 object 的區別?
  • 2、String 和 string 的區別?
  • 3、null 和 undefined 的區別?
  • 3、any、void、never、unknown 的區別?

1.1 String 和 string 的區別?

  • 思考下面的程式碼
'123' === new String('123') // ??
// false
typeof new String('123') // ??
// object
 
 //b 包裝型別
let a = '123', b = new String('123');
a.name = b.name = 'string';
console.log(a.name, b.name); // ??
複製程式碼

上面的 a.name 會列印 undefined,b.name 可以正常的列印出 'string'

區分原始型別和包裝型別(wrapper object)

  • 而TS中的string、boolean、number等宣告型別,則是指原始的基本資料型別。
let str: string = new String(123); // error: Type 'String' is not assignable to type 'string'.
let str: string = '123'; // ok
let str: String = '123'; // ok
 
let a = new String(1234);
let: str: typeof '1234'; // str: string
let str: typeof a; //str: String
複製程式碼

2.1 Object 和 object 的區別?

  • 在js中,Boolean、String、Number為基本包裝型別的建構函式(類)。在TS中,他們在型別宣告上下文中,則指代介面定義:
interface String {
    /** Returns a string representation of a string. */
    toString(): string;
 
    /**
      * Returns the character at the specified index.
      * @param pos The zero-based index of the desired character.
      */
    charAt(pos: number): string;
 
    /**
      * Returns the Unicode value of the character at the specified location.
      * @param index The zero-based index of the desired character. If there is no character at the specified index, NaN is returned.
      */
    charCodeAt(index: number): number;
 
 
    ...
}

複製程式碼

即,在TS中,new String(...) 這裡的String是指對於interface String的類實現(class implements)。

  • 而在型別宣告上下文中,String則指的就是這個interface String。

  • 2.1.1 Object 其實也是一個介面宣告,可以去看看 ts 原始碼的 Object 是怎麼宣告的。任意型別都是 Object

let num: Object = 1; // ok
let str: Object = 'a'; // ok
let obj: Object = { foo: 123 }; // ok
let nul: Object = null; // error
let undef: Object = undefined; // error
 
 
obj.foo // error: Property 'foo' does not exist on type '{}'
obj.toString() // ok
複製程式碼

事實上,宣告為Object可以賦予除了null、undefined以外的任意值!此時訪問這些宣告的變數,都可以訪問Object介面所定義的幾個基本方法。

  • 2.1.2 {}:而空的花括號{}型別,則和Object很類似,同樣可以接受任意型別的值。它是指空物件型別。宣告為{}型別,則沒有任何成員變數可以訪問(連Object.prototype.toString等方法都不可以)
let num: {} = 1; // ok
let str: {} = 'a'; // ok
let obj: {} = { foo: 1234 }; // ok
let nul: {} = null; // error
let undef: {} = undefined; // error
 
 
obj.foo // error: Property 'foo' does not exist on type '{}'
obj.toString() // error: Property 'toString' does not exist on type '{}'

複製程式碼
  • 2.1.3 object : object型別,則單純指代非string、number、boolean、symbol、null、undefined的其他型別!與{}類似,同樣沒有任何成員屬性或方法可以訪問!
// 這麼賦值
let num: object = 1; // error
let str: object = 'a'; // error
let obj: object = { foo: 1234 }; // ok
let nul: object = null; // error
let undef: object = undefined; // error
 
 
obj.foo // error: Property 'foo' does not exist on type 'object'
obj.toString() // error: Property 'toString' does not exist on type 'object'

複製程式碼
  • 型別的檢測的寬泛度:型別限制範圍上:any > {} ~ Object > object

總結: 表示基本物件型別時,應當總是使用object型別,或者使用介面定義結構化物件。

3.1 null 和 undefined 的區別?

  • ts中也有null和undefined型別,宣告為這兩種型別的值,也只能賦予同名值:
let a: null = null;
let b: undefined = undefined;
複製程式碼
  • 在預設情況下,null和undefined這兩個值(不是指型別!!)被當作其他型別的子型別,即可以賦予任意其他型別宣告的變數。但是在開啟了 --strictNullChecks 編譯選項後,他們則只能被賦予void型別,或者各自的同名型別。
let a: void = null;
let b: void = undefined;
複製程式碼

4.1 any、void、never、unknown 的區別

  • 4.1.1 any ts 檢測弱,相容性問題解決方案。
  • 成員訪問無限制
let user: any = {};
 
user.name // ok
複製程式碼

如以上例子中,user被宣告為any型別,即使其沒有name這個屬性,tsc也不會對其進行檢查。所以any可以用來指代哪些由外部傳入、服務端返回等黑盒子結構的資料!!

  • 事實上,任意未明確宣告型別並切無法推匯出型別的值都預設為any型別。
let a; // a: any
a = 1;
let a = 1; //a: number
複製程式碼
  • 4.1.2 void

void應當僅僅用於函式宣告,即沒有明確返回值的函式,應該被宣告為void型別。將void使用者變數宣告,則只能為其賦予null或undefined。

  • 4.1.3 never

never用於函式返回值時,表示函式有丟擲異常,沒有正常執行到底。用於變數宣告,無法為其賦予任何值!

never是所有型別的子型別並且可以賦值給所有型別。 沒有型別是never的子型別或能賦值給never(never型別本身除外)。

在函式表示式或箭頭函式沒有返回型別註解時,如果函式沒有return語句,或者只有never型別表示式的return語句,並且如果函式是不可執行到終點的(例如通過控制流分析決定的),則推斷函式的返回型別是never。

在有明確never返回型別註解的函式中,所有return語句(如果有的話)必須有never型別的表示式並且函式的終點必須是不可執行的。

  • never還可以用於對映型別中表示式,用於刪除/過濾當前型別
let a: string | never; // a: string
type Exclude<T, K> = T extends K ? never: T;
複製程式碼
  • 4.1.4 unknown

unknown相對於any,任意型別都可以賦值給unknow,但是不可對其進行任何訪問操作(僅僅為型別安全,any操作訪問也安全)

let a: any = 123;
a.toFixed(); //ok
let a: unknown = 123;
a.toFixed(); // error
複製程式碼

未完待續...