關(guān)于TypeScript
TypeScript是JavaScript的超集,主要提供類(lèi)型系統(tǒng)和對(duì)ES6的支持,由Microsoft開(kāi)發(fā),第一個(gè)版本發(fā)布于2012
TypeScript的優(yōu)勢(shì)
-
TypeScript增加了代碼的可讀性和可維護(hù)性- 大部分的函數(shù)函數(shù)看看類(lèi)型的定義就已經(jīng)知道該如何使用了
- 可以在編譯的階段就發(fā)現(xiàn)了大量的錯(cuò)誤,防止在運(yùn)行中發(fā)現(xiàn)過(guò)多的錯(cuò)誤
- 增強(qiáng)了編輯器和
IDE的功能。
-
TypeScript非常的包容-
TypeScript是JavaScript的超集,.js文件可以直接將名字轉(zhuǎn)換為.ts即可 - 即使不顯式的定義類(lèi)型,也可以自動(dòng)的做出類(lèi)型的推論
- 可以定義從簡(jiǎn)單到復(fù)雜的一切類(lèi)型
- 即使
TypeScript編譯報(bào)錯(cuò),也可以生成JavaScript文件
-
TypeScript的劣勢(shì)
- 需要一定的學(xué)習(xí)成本,需要理解接口(
Interfaces)、泛型(Generics)、類(lèi)(Classes)、枚舉類(lèi)型(Enums)等前端工程師不是很熟悉的東西,而且現(xiàn)階段的中文資料也不是很多 - 短期內(nèi)可能增加一些開(kāi)發(fā)成本,畢竟要多寫(xiě)一些類(lèi)型的定義,不過(guò)對(duì)于一個(gè)需要長(zhǎng)期進(jìn)行維護(hù)的額項(xiàng)目。
TypeScript能夠減少維護(hù)的成本 - 集成到構(gòu)建流程需要一定的工作量
- 可能和一些庫(kù)結(jié)合的并不是很完美
原始數(shù)據(jù)類(lèi)型
對(duì)于前端開(kāi)發(fā)來(lái)說(shuō),主要的類(lèi)型可以 分成兩部分:原始數(shù)據(jù)類(lèi)型和對(duì)象類(lèi)型。原始數(shù)據(jù)類(lèi)型包括:布爾值,數(shù)值,字符串,null,undefined以及ES6中的新類(lèi)型symbol?,F(xiàn)在我們主要看一下這些原始值在TypeScript中的應(yīng)用。
布爾值
布爾值是最基本的數(shù)據(jù)類(lèi)型,在TypeScript中,使用Boolean定義布爾值類(lèi)型:
let isTrue:boolean = false;
// 可以通過(guò)編譯
// 對(duì)于后面來(lái)說(shuō),沒(méi)有特殊強(qiáng)調(diào)錯(cuò)誤代碼片段,就默認(rèn)為編譯通過(guò)了。
注意一下,使用構(gòu)造函數(shù)Boolean創(chuàng)建的對(duì)象不是布爾值:
let createdByNewBoolean : boolean = new Boolean(1);
// index.ts(1,5): error TS2322: Type 'Boolean' is not assignable to type 'boolean'.
上面代碼報(bào)錯(cuò)的原因是new Boolean()返回一個(gè)Boolean對(duì)象:
let createdByNewBoolean : Boolean= new Boolean(1);
直接調(diào)用Boolean也可以返回一個(gè) boolean 類(lèi)型:
let createdByBoolean: boolean = Boolean(1);
在TypeScript中,boolean 是 JavaScript中的基本類(lèi)型,而Boolean 是 JavaScript 中的構(gòu)造函數(shù)。其他基本類(lèi)型(除了 null和 undefined)一樣,不再贅述。
數(shù)值
使用nubmber定義數(shù)值類(lèi)型:
let decLiteral:number=6;
let hexLiteral:number = 0xf00d;
let binaryLiteral:number = 0b1010; // ES6中的二進(jìn)制表示法
let octalLiteral:number =0o744;// ES6中的八進(jìn)制表示法
let notNumber:number =NaN;
let infinityNumber:number = Infinity;
上面的編譯的結(jié)果是什么:
var decLiteral = 6;
var hexLiteral = 0xf00d;
var binaryLiteral = 10;
var octalLiteral= 484;
var notNumber = NaN;
var infinityNumber = Infinity;
其中0b1010 和 0o744 是ES6 中的二進(jìn)制和八進(jìn)制表示法,它們會(huì)被編譯為十進(jìn)制數(shù)字。
字符串
使用string定義字符串類(lèi)型:
// 普通字符串
let myName:string = 'kim';
let myAge:number = 25;
// 模板字符串
let sentence:string = `Hello,my name is ${myName}.
I'll be ${myAge + 1} years old next month`;
編譯結(jié)果:
var myName = 'kim';
var myAge = 25;
// 模板字符串
let sentence = "Hello,my name is"+myName+".\nI'will be"+(myAge+1)+"years old next month";
空值
JavaScript沒(méi)有空值(void)的概念,在TypeScript中,可以用void表示沒(méi)有任何返回值的函數(shù)。
function akertName():void{
alert('My name is kim');
}
聲明一個(gè)void類(lèi)型變量是沒(méi)有什么用,因?yàn)槲覀冎荒軐⑺x值為undefined和null:
let unusable:void = undefined
Null和undefined
在TypeScript中,可以使用null和undefined來(lái)定義這兩個(gè)原始數(shù)據(jù)類(lèi)型:
let u:undefined = undefined;
let n:null = null;
undefined只能賦值為undefined,null只能賦值為null。但是這二者和void還是有區(qū)別的,null和undefined是所有類(lèi)型的子類(lèi)型,也就是說(shuō)undefined類(lèi)型的變量,可以賦值給number類(lèi)型的變量:
//這樣寫(xiě)也是沒(méi)有問(wèn)題的
let num:number =undefined;
let u: undefined;
let num: number = u;
但是void的類(lèi)型并不是這樣的,不能講void類(lèi)型的變量不能賦值給number類(lèi)型的變量:
let u: void;
let num: number = u;
//index.ts(2,5): error TS2322: Type 'void' is not assignable to type 'number'.
任意值
任意值(Any)用來(lái)表示允許賦值為任意類(lèi)型。
什么是任意值類(lèi)型
如果是一個(gè)普通類(lèi)型,在賦值過(guò)程中改變類(lèi)型是不被允許的:
let myFavoriteNumber:string ='seven';
myFavoriteNumber = 7;
// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
但如果是 any 類(lèi)型,則允許被賦值為任意類(lèi)型。
let myFavoriteNumber : any ='seven';
myFavoriteNumber = 7;
任意值的屬性和方法
在任何值上訪問(wèn)任何屬性都是允許的:
let anyThing :any = 'hello';
console.log(anyThing.myName);
console.log(anyThing.myName.firstName);
也允許調(diào)用任何方法:
let anyThing : any = 'kim';
anyThing.setName('Tom');
anyThing.setName('Tom').sayHello();
anyThing.myName.setFirstName('kim');
可以認(rèn)為,聲明一個(gè)變量為任意值之后,對(duì)它的任何操作,返回的內(nèi)容的類(lèi)型都是任意值。
未聲明類(lèi)型的變量
變量如果在聲明的時(shí)候,未指定其類(lèi)型,那么它會(huì)被識(shí)別為任意值類(lèi)型:
let something;
something = 'seven';
something = 7;
something.setName('kim');
上面的代碼等價(jià)于:
let something:any;
something = 'seven';
something = 7;
something.setName('kim');
類(lèi)型推論
如果沒(méi)有明確的字段,那么TypeScript會(huì)依照類(lèi)型推論的規(guī)則判斷出一個(gè)類(lèi)型。
下面的代碼雖然沒(méi)有指定類(lèi)型,但是會(huì)在編譯的時(shí)候報(bào)錯(cuò):
let myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
上面的代碼等價(jià)于:
let myFavoriteNumber:string = 'seven';
myFavoriteNumber = 7;
// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
但是為什么這和any類(lèi)型的還是有區(qū)別的,二者的區(qū)別在于在聲明的時(shí)候沒(méi)有賦值的話,就會(huì)判斷成any類(lèi)型,在后續(xù)就不會(huì)再進(jìn)行檢查。
聯(lián)合類(lèi)型
聯(lián)合類(lèi)型表示取值可以為多種類(lèi)型中的一種。
讓我們先舉個(gè)小栗子:
let myFavoriteNumber:string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
上面的例子說(shuō)明myFavoriteNumber可以是string類(lèi)型或是number類(lèi)型的。但是如果我們給這個(gè)值給一個(gè)布爾值,就會(huì)報(bào)錯(cuò)。
let myFavoriteNumber:string | number;
myFavoriteNumber = true;
// index.ts(2,1): error TS2322: Type 'boolean' is not assignable to type 'string | number'.
// Type 'boolean' is not assignable to type 'number'.
聯(lián)合類(lèi)型使用 | 分隔每個(gè)類(lèi)型。
這里的string|number的意思是,允許myFavoriteNumber的類(lèi)型是string或是number,但是不能是其他類(lèi)型。
訪問(wèn)聯(lián)合類(lèi)型的屬性或方法
當(dāng)TypeScript不確定一個(gè)聯(lián)合類(lèi)型的變量到底是哪個(gè)類(lèi)型的時(shí)候,我們只能訪問(wèn)此聯(lián)合類(lèi)型的所有類(lèi)型里共有的屬性和方法:
function getLength(something: string | number): number {
return something.length;
}
// index.ts(2,20): error TS2339: Property 'length' does not exist on type 'string | number'.
// Property 'length' does not exist on type 'number'.
上例中,length 不是string 和 number 的共有屬性,所以會(huì)報(bào)錯(cuò)。
訪問(wèn) string 和 number 的共有屬性是沒(méi)問(wèn)題的:
function getString(something:string | number):string{
return something.toString();
}
聯(lián)合類(lèi)型的變量在被賦值的時(shí)候,會(huì)根據(jù)類(lèi)型推論的規(guī)則推斷出一個(gè)類(lèi)型:
let myFavoriteNumber:string|number;
myFavoriteNumber = 'seven';
console.log(myFavoriteNumber.length); // 5
myFavoriteNumber = 7;
console.log(myFavoriteNumber.length); // 編譯時(shí)報(bào)錯(cuò)
// index.ts(5,30): error TS2339: Property 'length' does not exist on type 'number'.
上例中,第二行的 myFavoriteNumber被推斷成了 string,訪問(wèn)它的length屬性不會(huì)報(bào)錯(cuò)。
而第四行的myFavoriteNumber 被推斷成了 number,訪問(wèn)它的 length屬性時(shí)就報(bào)錯(cuò)了。
對(duì)象的類(lèi)型 -- 接口
在TypeScript中,我們使用接口來(lái)定義對(duì)象的類(lèi)型。
什么是接口
在面向?qū)ο蟮恼Z(yǔ)言中,接口是一個(gè)很重要的概念,他是對(duì)行為的抽象,而具體如何行動(dòng)需要類(lèi)去實(shí)現(xiàn)。TypeScript中的接口就是一個(gè)很靈活的概念,除了可用于對(duì)類(lèi)的一部分行為進(jìn)行抽象以外,也常用于對(duì)【對(duì)象的形狀】進(jìn)行描述。
簡(jiǎn)單的例子:
interface Person{
name:string;
age:number;
}
let kim:Person={
name:'kim',
age:18
}
在上面的例子中我們定義了一個(gè)接口Person,接著定義可一個(gè)變量kim,它的類(lèi)型是person,這樣,我們就約束了kim的形狀和接口Person一致。
接口一般首字母大寫(xiě)。
接口的變量比接口少一些或是多一些屬性是不允許的:
interface Person {
name: string;
age: number;
}
let kim: Person = {
name: 'kim',
};
// index.ts(6,5): error TS2322: Type '{ name: string; }' is not assignable to type 'Person'.
// Property 'age' is missing in type '{ name: string; }'.
interface Person {
name: string;
age: number;
}
let kim: Person = {
name: 'kim,
age: 25,
website: 'http://kim.com',
};
// index.ts(9,3): error TS2322: Type '{ name: string; age: number; website: string; }' is not assignable to type 'Person'.
// Object literal may only specify known properties, and 'website' does not exist in type 'Person'.
可選屬性
有的時(shí)候我們希望不要完全匹配成一個(gè)形狀,那么我們可用一些可選屬性:
interface Person {
name: string;
age?: number;
}
let kim: Person = {
name: 'kim',
};
let kimi: Person = {
name: 'kimi',
age:28
};
可選屬性的意思就是這個(gè)屬性的值可以是不存在的,但是在這種情況下依舊不允許添加未定義的屬性,我們?cè)谙旅媾e個(gè)栗子:
let Tom: Person = {
name: 'Tom',
age:28,
website:'http://www.baidu.com',
};
// examples/playground/index.ts(9,3): error TS2322:
// Type '{ name: string; age: number; website: string; }' is not assignable to type 'Person'.
// Object literal may only specify known properties, and 'website' does not exist in type 'Person'.
任意屬性
有的時(shí)候我們希望幾口允許任意的屬性,可以使用如下的方式:
interface Person{
name:string;
age?:number;
[propName:string]:any;
}
let kim :Person ={
name:'kim',
website:'http://www.baidu.com',
};
我們對(duì)于上面的代碼進(jìn)行解析,使用[propName:string]定義了任意屬性取string類(lèi)型的值。但是需要注意的是,一旦定義了任意屬性,那么確定屬性和可選屬性都必須是它的子屬性:
interface Person{
name:string;
age?:number;
[propName:string]:string;
}
let kim :Person ={
name:'kim',
age:25,
website:'http://www.baidu.com',
}
// index.ts(3,3): error TS2411:
//Property 'age' of type 'number' is not assignable to string index type 'string'.
// index.ts(7,5):
//error TS2322: Type '{ [x: string]: string | number; name: string; age: number; website: string; }' is not
//assignable to type 'Person'.
// Index signatures are incompatible.
//Type 'string | number' is not assignable to type 'string'.
//Type 'number' is not assignable to type 'string'.
上例中,任意屬性的值允許是 string,但是可選屬性 age 的值卻是number,number 不是string的子屬性,所以報(bào)錯(cuò)了。
另外,在報(bào)錯(cuò)信息中可以看出,此時(shí) { name: ‘Xcat Liu’, age: 25, website: ‘http://xcatliu.com’ } 的類(lèi)型被推斷成了 { [x: string]: string | number; name: string; age: number; website: string; },這是聯(lián)合類(lèi)型和接口的結(jié)合。
只讀屬性
有時(shí)候我們希望對(duì)象中的一些字段只能在創(chuàng)建的時(shí)候被賦值,那么可以用readonly定義只讀屬性:
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let xcatliu: Person = {
id: 89757,
name: 'kim',
website: 'http://www.baidu.com',
};
xcatliu.id = 9527;
// index.ts(14,9): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.
上面的id屬性是只讀屬性,id在初始化之后,又被賦值了,所以會(huì)報(bào)錯(cuò)。只讀的約束存在于第一次給對(duì)象賦值的時(shí)候,而不是第一次給只讀屬性賦值的時(shí)候。
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let xcatliu: Person = { // 沒(méi)有給id進(jìn)行賦值
name: 'Xcat Liu',
website: 'http://xcatliu.com',
};
xcatliu.id = 89757; // 錯(cuò)誤
// index.ts(8,5): error TS2322: Type '{ name: string; website: string; }' is not assignable to type 'Person'.
// Property 'id' is missing in type '{ name: string; website: string; }'.
// index.ts(13,9): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.
數(shù)組的類(lèi)型
[類(lèi)型+方括號(hào)]表示法
最簡(jiǎn)單的方法是使用[類(lèi)型+方括號(hào)]來(lái)標(biāo)識(shí)數(shù)組:
let arr:number[] =[1,2,3,4,5]
數(shù)組的項(xiàng)中不允許出現(xiàn)其他的類(lèi)型:
let arr:number[] =[1,'2',3,4,5];
//index.ts(1,5): error TS2322: Type '(number | string)[]' is not assignable to type 'number[]'.
//Type 'number | string' is not assignable to type 'number'.
//Type 'string' is not assignable to type 'number'.
現(xiàn)在的[1,'2',3,4,5]的類(lèi)型被推斷稱(chēng)為(number|string)[],這個(gè)是聯(lián)合類(lèi)型和數(shù)組的結(jié)合。
let arr2: number[] = [1,2,3,4,5,6,7];
arr2.push('8')
//index.ts(2,16): error TS2345: Argument of type 'string' is
//not assignable to parameter of type 'number'.
數(shù)組泛型
也可以使用數(shù)組泛型(Generic) Array<elemType> 來(lái)表示數(shù)組:
let arr3: Array<number> = [1, 1, 2, 3, 5];
用接口表示數(shù)組
接口也可以用來(lái)描述數(shù)組:
interface NumberArray{
[index:number]:number;
}
let arr4 : NumberArray=[1,1,2,3,4];
NumberArray 表示:只要 index 的類(lèi)型是 number,那么值的類(lèi)型必須是 number。
any 在數(shù)組中的應(yīng)用
一個(gè)比較常見(jiàn)的做法是,用any表示數(shù)組中允許出現(xiàn)任意類(lèi)型:
let list : any[] =['kim',25,{website:'www.baidu.com'}];
類(lèi)數(shù)組
類(lèi)數(shù)組不是數(shù)組類(lèi)型,比如arguments:
function sum(){
let args:number[] = arguments;
}
// index.ts(2,7): error TS2322: Type 'IArguments' is not assignable to type 'number[]'.
// Property 'push' is missing in type 'IArguments'.
事實(shí)上常見(jiàn)的類(lèi)數(shù)組都有自己的接口定義,如 Arguments,NodeList, HTMLCollection 等:
function sum() {
let args: IArguments = arguments;
}
函數(shù)的類(lèi)型
函數(shù)的聲明
在JavaScript中,有兩種常見(jiàn)的定義函數(shù)的方式--函數(shù)聲明(Function Declaration)和函數(shù)表達(dá)式(Function Expression):
// 函數(shù)聲明(Function Declaration)
function sum (x,y){
return x+y;
}
//函數(shù)表達(dá)式(Function Expression)
let mySum = function (x,y){
return x + y;
}
一個(gè)函數(shù)有輸入和輸出,要在TypeScript中對(duì)齊進(jìn)行約束,需要把輸入和輸出都考慮到,其中函數(shù)聲明的類(lèi)型定義比較簡(jiǎn)單:
function sum (x:number,y:number):number{
return x+y;
}
但是輸出多余的(或少于要求)參數(shù),是不被允許的:
function sum (x:number,y:number):number{
return x+y;
}
sum (1,2,3);
// index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.
sum (1);
//index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.
函數(shù)表達(dá)式
如果我們現(xiàn)在想要寫(xiě)一個(gè)函數(shù)表達(dá)式的定義,我們可能會(huì)這樣寫(xiě):
let muSum = function(x:number,y:number):number{
return x+y;
}
這個(gè)是可以通過(guò)編譯的,但是在事實(shí)上,上面的代碼只對(duì)等號(hào)右側(cè)的匿名行數(shù)進(jìn)行了類(lèi)的定義,而等號(hào)左側(cè)的mySum,是通過(guò)賦值操作對(duì)類(lèi)型進(jìn)行推斷出來(lái)的。如果需要我們手動(dòng)給mySum添加類(lèi)型,代碼應(yīng)該只這樣寫(xiě)的:
let mySum:(x number,y:number) =>number = function (x:number,y:number):number{
return x+y;
}
在TypeScript的類(lèi)型定義中,=>用來(lái)表示函數(shù)的定義,左邊是輸入類(lèi)型,需要用括號(hào)括起來(lái),右邊是輸出類(lèi)型,應(yīng)用是十分廣泛的。
接口中函數(shù)的定義
我們也可以使用接口的當(dāng)時(shí)來(lái)定義一個(gè)函數(shù)需要符合的形象:
interface SearchFunc{
(source:string,subString:string):boolean
}
let mySearch : SearchFunc;
mySearch = function (source:string,subString:string){
return source.search(subString) !== -1;
}
可選參數(shù)
前面,輸入多余的(或是少于要求的)的參數(shù),是不被允許的,那么怎么定義可選的參數(shù)呢?與接口中的可選屬性相似,也是使用?表示可選參數(shù):
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
let kimXue= buildName('Xcat', 'Xue');
let kim= buildName('kim');
需要注意的是,可選參數(shù)必須接在必需參數(shù)后面。換句話說(shuō),可選參數(shù)后面不允許再出現(xiàn)必須參數(shù)了:
function buildName(firstName?: string, lastName: string) {
if (firstName) {
return firstName + ' ' + lastName;
} else {
return lastName;
}
}
let kimXue= buildName('Xcat', 'Xue');
let kim= buildName('kim');
// index.ts(1,40): error TS1016: A required parameter cannot follow an optional parameter.
上面的代碼會(huì)報(bào)錯(cuò),因?yàn)樵趂irst那么這個(gè)屬性的后面還有必須的屬性,因此報(bào)錯(cuò)。
參數(shù)默認(rèn)值
在ES6中,我們?cè)试S給函數(shù)的參數(shù)添加默認(rèn)值,TypeScript會(huì)將添加了默認(rèn)值的參數(shù)識(shí)別為可選參數(shù):
function buildName(firstName: string, lastName: string = 'Xue') {
return firstName + ' ' + lastName;
}
let kimXue= buildName('Xcat', 'Xue');
let kim= buildName('kim');
此時(shí)就不受「可選參數(shù)必須接在必需參數(shù)后面」的限制了:
function buildName(firstName: string = 'kim', lastName: string) {
return firstName + ' ' + lastName;
}
let kimXue= buildName('Xcat', 'Xue');
let kim= buildName('kim');
剩余參數(shù)
ES6中,可以使用...rest的方式獲取函數(shù)中的剩余參數(shù)(rest參數(shù)):
function push(array,...items){
items.forEach(function (item){
array.push(item);
})
}
let a = [];
push(a,1,2,3);
事實(shí)上,items是一個(gè)數(shù)組,所以我們可以用數(shù)組的類(lèi)型去定義它:
function push(array:any[],...items:any[]){
items.forEach(function (item){
array.push(item);
})
}
let a = [];
push(a,1,2,3);
和上面的代碼一樣,rest參數(shù)只能是最后一個(gè)參數(shù)。
重載
重載允許一個(gè)函數(shù)接受不同數(shù)量或是類(lèi)型的參數(shù),并作出不同的處理。
比如,我們需要實(shí)現(xiàn)一個(gè)函數(shù)reverse,輸入數(shù)字123的時(shí)候,輸出的就是數(shù)字321,輸入字符串‘hello’的時(shí)候,輸出翻轉(zhuǎn)的字符串‘olleh’,利用聯(lián)合類(lèi)型,我們可以這么實(shí)現(xiàn):
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
然而這樣寫(xiě)的話,還是有一個(gè)缺點(diǎn),就是不能夠精確地表達(dá),輸入為數(shù)字的時(shí)候,輸出的也應(yīng)該是數(shù)字,輸入為字符串的時(shí)候,輸出也應(yīng)該為字符串。這時(shí),我們可以用重載來(lái)實(shí)現(xiàn)多個(gè)這樣的函數(shù):
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
類(lèi)型斷言
類(lèi)型斷言可以用來(lái)繞過(guò)編譯器的類(lèi)型判斷,手動(dòng)指定一個(gè)值的類(lèi)型。
語(yǔ)法
<類(lèi)型>值
// 或
值 as 類(lèi)型
// 在TSX語(yǔ)法 (React的JSX語(yǔ)法的TS版)中必須用后一種
例子:將一個(gè)聯(lián)合類(lèi)型的變量指定為一個(gè)更加具體的類(lèi)型
當(dāng) TypeScript 不確定一個(gè)聯(lián)合類(lèi)型的變量到底是哪個(gè)類(lèi)型的時(shí)候,我們只能訪問(wèn)此聯(lián)合類(lèi)型的所有類(lèi)型里共有的屬性或方法:
function getLength(something: string | number): number {
return something.length;
}
//index.ts(2,20): error TS2339: Property 'length' does not exist on type 'string | number'.
//Property 'length' does not exist on type 'number'.
這樣的時(shí)候我們就需要使用類(lèi)型斷言,現(xiàn)將something斷言成string:
function getLength(something: string | number): number {
if ((<string>something).length) {
return (<string>something).length;
} else {
return something.toString().length;
}
}
類(lèi)型斷言不是類(lèi)型轉(zhuǎn)換,斷言成一個(gè)聯(lián)合類(lèi)型中不存在的類(lèi)型是不允許的:
function toBoolean(something: string | number): boolean {
return <boolean>something;
}
// index.ts(2,10): error TS2352: Type 'string | number' cannot be converted to type 'boolean'.
// Type 'number' is not comparable to type 'boolean'.
聲明文件
當(dāng)我們使用第三方庫(kù)時(shí),我們需要引用它的聲明文件:
聲明語(yǔ)法
當(dāng)我們使用第三方庫(kù),比如jQuery,我們通常這樣獲取一個(gè)id是foo元素:
$('#foo');
// or
jQuery('#foo');
但是在 TypeScript 中,我們并不知道$ 或jQuery是什么東西。這時(shí),我們需要使用 declare關(guān)鍵字來(lái)定義它的類(lèi)型,幫助 TypeScript 判斷我們傳入的參數(shù)類(lèi)型對(duì)不對(duì)。
declear var jQuery:(string) =>any;
jQuery('#foo');
declare 定義的類(lèi)型只會(huì)用于編譯時(shí)的檢查,編譯結(jié)果中會(huì)被刪除。
聲明文件
通常我們會(huì)把類(lèi)型聲明放在一個(gè)單獨(dú)的文件中,這就是聲明文件:
// jQuery.d.ts
declare var jQuery: (string) => any;
我們約定聲明文件以.d.ts為后綴。
然后在使用到的文件的開(kāi)頭,用「三斜線指令」表示引用了聲明文件:
/// <reference path="./jQuery.d.ts" />
jQuery('#foo');