这是我参与更文挑战的第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会产生错误。