寫在最前面
- 最近學習 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); // ??
複製程式碼
區分原始型別和包裝型別(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
複製程式碼