這是我參與更文挑戰的第3天,活動詳情查看: 更文挑戰html
類型斷言,就是告訴ts我知道這個變量的類型是什麼,它沒有運行時的影響,只是在編譯階段起做用markdown
類型斷言有兩種形式。 其一是「尖括號」語法:app
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
另外一個爲as語法:
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
複製代碼
兩種形式是等價的。 至於使用哪一個大多數狀況下是憑我的喜愛;然而,當你在TypeScript裏使用JSX時,只有 as語法斷言是被容許的。dom
必要參數,默認參數和可選參數有個共同點:它們表示某一個參數。 有時,你想同時操做多個參數,或者你並不知道會有多少參數傳遞進來。 在JavaScript裏,你可使用 arguments來訪問全部傳入的參數。函數
在TypeScript裏,你能夠把全部參數收集到一個變量裏:oop
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;
複製代碼
JavaScript裏,this的值在函數被調用的時候纔會指定。 這是個既強大又靈活的特色,可是你須要花點時間弄清楚函數調用的上下文是什麼。 但衆所周知,這不是一件很簡單的事,尤爲是在返回一個函數或將函數當作參數傳遞的時候。post
let deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function() {
return function() {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
}
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
alert("card: " + pickedCard.card + " of " + pickedCard.suit);
複製代碼
能夠看到 createCardPicker 是個函數,而且它又返回了一個函數。 若是咱們嘗試運行這個程序,會發現它並無彈出對話框而是報錯了。 由於 createCardPicker返回的函數裏的 this 被設置成了 window 而不是deck對象。 由於咱們只是獨立的調用了 cardPicker()。 頂級的非方法式調用會將 this視爲window。 (注意:在嚴格模式下, this爲undefined而不是window)。ui
爲了解決這個問題,咱們能夠在函數被返回時就綁好正確的this。 這樣的話,不管以後怎麼使用它,都會引用綁定的‘deck’對象。 咱們須要改變函數表達式來使用ECMAScript 6箭頭語法。 箭頭函數能保存函數建立時的 this值,而不是調用時的值:this
let deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function() {
// NOTE: the line below is now an arrow function, allowing us to capture 'this' right here
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
}
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
alert("card: " + pickedCard.card + " of " + pickedCard.suit);
複製代碼
更好事情是,TypeScript會警告你犯了一個錯誤,若是你給編譯器設置了--noImplicitThis標記。 它會指出 this.suits[pickedSuit]裏的this的類型爲any。url
不幸的是,this.suits[pickedSuit]的類型依舊爲any。 這是由於 this來自對象字面量裏的函數表達式。 修改的方法是,提供一個顯式的 this參數。 this參數是個假的參數,它出如今參數列表的最前面:
你能夠也看到過在回調函數裏的this報錯,當你將一個函數傳遞到某個庫函數裏稍後會被調用時。 由於當回調被調用的時候,它們會被當成一個普通函數調用, this將爲undefined。 稍作改動,你就能夠經過 this參數來避免錯誤。 首先,庫函數的做者要指定 this的類型:
interface UIElement {
addClickListener(onclick: (this: void, e: Event) => void): void;
}
複製代碼
class Handler {
info: string;
onClickGood: (e: Event) => {
this.info = e.message;
}
}
let h = new Handler();
uiElement.addClickListener(h.onClickGood);
複製代碼
這是可行的由於箭頭函數不會捕獲this,因此你老是能夠把它們傳給指望this: void的函數。 缺點是每一個 Handler對象都會建立一個箭頭函數。 另外一方面,方法只會被建立一次,添加到 Handler的原型鏈上。 它們在不一樣 Handler對象間是共享的。
JavaScript自己是個動態語言。 JavaScript裏函數根據傳入不一樣的參數而返回不一樣類型的數據是很常見的。
pickCard方法根據傳入參數的不一樣會返回兩種不一樣的類型。 若是傳入的是表明紙牌的對象,函數做用是從中抓一張牌。 若是用戶想抓牌,咱們告訴他抓到了什麼牌。 可是這怎麼在類型系統裏表示呢。
方法是爲同一個函數提供多個函數類型定義來進行函數重載。 編譯器會根據這個列表去處理函數的調用。 下面咱們來重載 pickCard函數。
let suits = ["hearts", "spades", "clubs", "diamonds"];
function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; };
function pickCard(x): any {
// Check to see if we're working with an object/array
// if so, they gave us the deck and we'll pick the card
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
return pickedCard;
}
// Otherwise just let them pick the card
else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);
let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);
複製代碼
重載的pickCard函數在調用的時候會進行正確的類型檢查。
爲了讓編譯器可以選擇正確的檢查類型,它與JavaScript裏的處理流程類似。 它查找重載列表,嘗試使用第一個重載定義。 若是匹配的話就使用這個。 所以,在定義重載的時候,必定要把最精確的定義放在最前面。
注意,function pickCard(x): any並非重載列表的一部分,所以這裏只有兩個重載:一個是接收對象另外一個接收數字。 以其它參數調用 pickCard會產生錯誤。