let i = void 2; // i === undefined
複製代碼
Why 爲何須要void?javascript
由於早期js裏,人們能夠重寫undefined,而後賦予真正的值給它,而void老是返回真正的undefined。java
void function() {
console.log('what')
}()
複製代碼
void function aRecursion(i) {
if(i > 0) {
console.log(i--)
aRecursion(i)
}
}(3)
console.log(typeof aRecursion) // undefined
複製代碼
函數aRecursion執行完後當即釋放, 全局做用域也沒法獲取到這個引用。由於void老是能夠執行它後面的表達式。typescript
function middleware(nextcb) {
if(conditionApplies()){
return void nextcb();
}
}
複製代碼
undefined
,由於返回值是動態地,返回值可能會根據方法內的邏輯返回,可是void卻能夠100%保證返回undefined
。button.onclick = () => void doSomething();
複製代碼
定義安全
undefined
的子類型。用法bash
undefined
function () {
console.log('xx')
}
複製代碼
void
能夠做爲類型聲明中的參數。declare function iTakeNoParameters(x: void): void 複製代碼
此時只有
undefined
能夠做爲參數傳入函數
iTakeNoParameters(undefined) //
iTakeNoParameters(void 2) //
複製代碼
void
的最大特色在Typescript
中void
和undefined
最重要的一個區別: void
做爲函數返回值的類型時,能夠用不一樣的類型替換:ui
function doSomething(callback: () => void) {
// 這個回調會永遠返回undefined
let c = callback()
//c也是undefined類型
}
// 該返回返回number類型
function aNumberCallback(): number {
return 2;
}
// 其實這個方法就作到了類型安全。
doSomething(aNumberCallback)
複製代碼
這種稱爲typescirpt-substitutability
(可替換性模式), 若是但願傳遞函數是返回undefined
的,必須明確顯式指定回調的簽名是:() => undefined
this
建立Symbol很是簡單,使用Symbol
構造出來的實例具備惟一的值:spa
const ACADEMIC_TITLE = Symbol('title')
const ARTICLE_TITLE = Symbol('title')
if(ACADEMIC_TITLE === ARTICLE_TITLE) {
// 兩個Symbol永遠不會相同
}
複製代碼
Switch語句中使用Symbol
debug
const LEVEL_INFO = Symbol('INFO')
const LEVEL_DEBUG = Symbol('DEBUG')
const LEVEL_WARN = Symbol('WARN')
const LEVEL_ERROR = Symbol('ERROR')
function log(msg, level) {
switch(level) {
case LEVEL_WARN:
console.warn(msg); break
case LEVEL_ERROR:
console.error(msg); break;
case LEVEL_DEBUG:
console.log(msg);
debugger; break;
case LEVEL_INFO:
console.log(msg);
}
}
複製代碼
做爲對象的key
const print = Symbol('print')
const user = {
name: 'Stefan',
age: 37,
[print]: function() {
console.log(`${this.name} is ${this.age} years old`)
}
}
複製代碼
這裏只須要注意如下幾點,就是做爲對象的Key時,這個print
是不可枚舉的,同時它也是沒法被序列化的。
typescript
支持symbol
,它是類型系統中的基本類型。Symbol
自己是全部symbol
值的類型。 它也有一個sub-type
:稱爲unique symbol
, 它能夠聲明一個惟一的類型:
const PROD: unique symbol = Symbol('prodution mode');
const DEV: unique symbol = Symbol('Development mode');
複製代碼
能夠認爲是JS裏的一個名義類型值。爲了獲得它的類型須要用typeof
function showWarning(msg: string, mode: typeof DEV | typeof PROD) {
// ...
}
複製代碼
Symbols
是名義類型和結構類型之間的中間類型。 這是運行時最接近名義類型的類型,但本質上仍然不是名義類型。
運行時枚舉
ts的枚舉是結構類型,不是名義類型。 這表示你不能直接將string
值賦值給enum types
:
enum Colors {
Red = 'Red',
Yellow = 'yellow',
Blue = 'blue',
}
const c1: Colors = Colors.Blue;
// 這樣倒是不符合語法的 Type '"blue"'沒法賦值給'Colors'類型。
const c2: Colors = 'blue';
// false
console.log((Moods.Blue === Moods.Blue));
複製代碼
儘管是一樣的值,可是enum
裏面,就會變得獨一無二; 他們在TS裏是沒法比較的。
在JS裏的實現能夠使用Symbol來作到:
// All Color symbols
const COLOR_RED: unique symbol = Symbol('RED')
const COLOR_ORANGE: unique symbol = Symbol('ORANGE')
const COLOR_YELLOW: unique symbol = Symbol('YELLOW')
// create enum
const ColorsEnum = {
COLOR_RED,
COLOR_ORANGE,
COLOR_YELLOW,
} as const;
複製代碼
typescript
的switch
語句用法
function getHexValue(color) {
switch(color) {
case Colors.COLOR_RED: return '#ff0000'
//...
}
}
複製代碼
編譯機時以及運行時的類型安全
unique symbol
時,全部的賦值都不能改變。const
聲明,TypeScript
就會只容許傳入的定義好的Symbol
類型。// 索引類型
type ValuesWithKeys<T, K extends keyof T> = T[K];
type Values<T> = ValuesWithKeys<T, keyof T>;
複製代碼
解釋
index types
索引類型:爲了從對象中選取屬性的子集,編譯器可以檢查使用了動態屬性名即索引類型。
// 如下這種索引類型就是爲了提示編譯器去檢查: 傳入的參數names中是否爲o類型的一個屬性。
function pluck<T, K extends keyof T>(o: T, names: k[]): T[K][] {
return names.map(n => o[n]);
}
// 索引類型能夠做爲函數的類型;, T[K]表示了必須是T類型中的屬性。
複製代碼
而後利用索引類型,能夠在聲明函數時,將color
類型縮窄至只容許Colors
類型,而且是Symbol
的鍵和值,而不是隻有Symbol
自己的值。
const ColorEnum = {
[COLOR_RED]: COLOR_RED,
[COLOR_YELLOW]: COLOR_YELLOW,
[COLOR_ORANGE]: COLOR_ORANGE,
[COLOR_GREEN]: COLOR_GREEN,
[COLOR_BLUE]: COLOR_BLUE,
[COLOR_INDIGO]: COLOR_INDIGO,
[COLOR_VIOLET]: COLOR_VIOLET,
}
function getHexValue(color: Values<typeof Colors>) {
switch(color) {
case COLOR_RED:
// super fine, is in our type
case Colors.COLOR_BLUE:
// also super fine, is in our type
break;
case COLOR_BLACK:
// what? What is this??? TypeScript errors 💥
break;
}
}
複製代碼
這樣就作到了不只在編譯時利用了TypeScript
的unique symbol
來保證類型安全性,同時在運行時也能夠經過JavaScript
中Symbol
獨一無二的特性實現類型安全。