typescript學(xué)習(xí)(一)
官網(wǎng)的介紹為:TypeScript 是 JavaScript 的類(lèi)型的超集,它可以編譯成純 JavaScript嗅榕。編譯出來(lái)的 JavaScript 可以運(yùn)行在任何瀏覽器上室奏。實(shí)際上就是規(guī)定了一種強(qiáng)類(lèi)型的寫(xiě)法火焰,加入了一個(gè)將ts代碼編譯為js代碼的過(guò)程,可以在編譯過(guò)程中及時(shí)發(fā)現(xiàn)錯(cuò)誤胧沫,而不是等到運(yùn)行時(shí)在頁(yè)面上瞎雞兒點(diǎn)昌简,然后發(fā)現(xiàn)是變量類(lèi)型錯(cuò)誤,變量名寫(xiě)錯(cuò)這種糟心的bug绒怨。這種的Uncaught TypeError
就很影響寫(xiě)代碼時(shí)的心情纯赎。
安裝與使用
TypeScript 的命令行工具安裝方法如下:
npm install -g typescript
以上命令會(huì)在全局環(huán)境下安裝 tsc
命令,安裝完成之后南蹂,我們就可以在任何地方執(zhí)行 tsc
命令了犬金。
編譯一個(gè) TypeScript 文件很簡(jiǎn)單:
tsc hello.ts
我們約定使用 TypeScript 編寫(xiě)的文件以 .ts
為后綴
優(yōu)勢(shì)與不足
TypeScript 增加了代碼的可讀性和可維護(hù)性
- 類(lèi)型系統(tǒng)實(shí)際上是最好的文檔,大部分的函數(shù)看看類(lèi)型的定義就可以知道如何使用了
- 可以在編譯階段就發(fā)現(xiàn)大部分錯(cuò)誤,這總比在運(yùn)行時(shí)候出錯(cuò)好
- 增強(qiáng)了編輯器和 IDE 的功能晚顷,包括代碼補(bǔ)全峰伙、接口提示、跳轉(zhuǎn)到定義音同、重構(gòu)等
TypeScript 非常包容
- TypeScript 是 JavaScript 的超集词爬,
.js
文件可以直接重命名為.ts
即可 - 即使不顯式的定義類(lèi)型,也能夠自動(dòng)做出類(lèi)型推論
- 可以定義從簡(jiǎn)單到復(fù)雜的幾乎一切類(lèi)型
- 即使 TypeScript 編譯報(bào)錯(cuò)权均,也可以生成 JavaScript 文件
- 兼容第三方庫(kù)顿膨,即使第三方庫(kù)不是用 TypeScript 寫(xiě)的,也可以編寫(xiě)單獨(dú)的類(lèi)型文件供 TypeScript 讀取
TypeScript 的缺點(diǎn)
任何事物都是有兩面性的叽赊,我認(rèn)為 TypeScript 的弊端在于:
- 有一定的學(xué)習(xí)成本恋沃,需要理解接口(Interfaces)、泛型(Generics)必指、類(lèi)(Classes)囊咏、枚舉類(lèi)型(Enums)等前端工程師可能不是很熟悉的概念
- 短期可能會(huì)增加一些開(kāi)發(fā)成本,畢竟要多寫(xiě)一些類(lèi)型的定義塔橡,不過(guò)對(duì)于一個(gè)需要長(zhǎng)期維護(hù)的項(xiàng)目梅割,TypeScript 能夠減少其維護(hù)成本
- 集成到構(gòu)建流程需要一些工作量
- 可能和一些庫(kù)結(jié)合的不是很完美
基本使用
JavaScript 的類(lèi)型分為兩種:原始數(shù)據(jù)類(lèi)型(Primitive data types)和對(duì)象類(lèi)型(Object types)。
原始數(shù)據(jù)類(lèi)型包括:布爾值葛家、數(shù)值户辞、字符串、null
癞谒、undefined
以及 ES6 中的新類(lèi)型 Symbol
底燎。
基本類(lèi)型
boolean
布爾值是最基礎(chǔ)的數(shù)據(jù)類(lèi)型,在 TypeScript 中弹砚,使用 boolean
定義布爾值類(lèi)型:
//編譯通過(guò)
let isDone: boolean = false;
//使用構(gòu)造函數(shù)生成的不是boolean值双仍,而是一個(gè)對(duì)象
let createdByNewBoolean: boolean = new Boolean(1);
//可以使用Boolean方法返回一個(gè)boolean值
let createdByBoolean: boolean = Boolean(1);
數(shù)值
***
字符串
***
空值
JavaScript 沒(méi)有空值(Void)的概念,在 TypeScript 中桌吃,可以用 void
表示沒(méi)有任何返回值的函數(shù):
function alertName(): void {
alert('My name is Tom');
}
聲明一個(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;
與 void
的區(qū)別是茅诱,undefined
和 null
是所有類(lèi)型的子類(lèi)型为流。也就是說(shuō) undefined
類(lèi)型的變量,可以賦值給 number
類(lèi)型的變量:
// 這樣不會(huì)報(bào)錯(cuò)
let num: number = undefined;
// 這樣也不會(huì)報(bào)錯(cuò)
let u: undefined;
let num: number = u;
any類(lèi)型
我們知道typescript是強(qiáng)類(lèi)型的让簿,因此是不允許在賦值過(guò)程中改變變量的類(lèi)型敬察,若變量的類(lèi)型在程序運(yùn)行過(guò)程中真的需要改變,那么我們可以將其定義為any類(lèi)型
let myFavoriteNumber: any = 'seven';
myFavoriteNumber = 7;
對(duì)于未顯式聲明類(lèi)型且未進(jìn)行初始化的變量尔当,它默認(rèn)會(huì)被指定為any
let something;
something = 'seven';
something = 7;
對(duì)于未顯式對(duì)于未顯式聲明類(lèi)型但是進(jìn)行過(guò)初始化的變量莲祸,會(huì)進(jìn)行類(lèi)型推斷
let myFavoriteNumber = 'seven';
//事實(shí)上等同于
let myFavoriteNumber: string = 'seven';
聯(lián)合類(lèi)型
我們也可以對(duì)一個(gè)變量指定多個(gè)類(lèi)型蹂安,在賦值時(shí),ts也根據(jù)所賦值進(jìn)行類(lèi)型推斷
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
并且我們可以訪問(wèn)這些類(lèi)型的公共方法或者屬性
function getString(something: string | number): string {
return something.toString();
}
Interfaces類(lèi)型
在 TypeScript 中锐帜,我們使用接口(Interfaces)來(lái)定義對(duì)象的類(lèi)型田盈。
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
在使用定義的接口類(lèi)型時(shí),性新對(duì)象內(nèi)少一些或者多一些屬性都是不被允許的缴阎,有時(shí)我們希望不要完全匹配一個(gè)接口允瞧,那么可以用可選屬性
interface Person {
name: string;
age?: number;
}
let tom: Person = {
name: 'Tom'
};
若我們需要添加接口內(nèi)沒(méi)有的屬性,那么可使用任意屬性蛮拔,
interface Person {
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
name: 'Tom',
gender: 'male'
};
需要注意的是述暂,一旦定義了任意屬性,那么確定屬性和可選屬性的類(lèi)型都必須是它的類(lèi)型的子集:
interface Person {
name: string;
age?: number;
[propName: string]: string;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
此時(shí)會(huì)報(bào)錯(cuò)建炫,age會(huì)被先于任意屬性做匹配畦韭,此時(shí)需要的是string類(lèi)型,可以該為下面這種用法
interface Person {
name: string;
age?: number;
[propName: string]: string | number;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
只讀屬性
有時(shí)候我們希望對(duì)象中的一些字段只能在創(chuàng)建的時(shí)候被賦值肛跌,那么可以用 readonly
定義只讀屬性:
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
id: 89757,
name: 'Tom',
gender: 'male'
};
tom.id = 9527;
// index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property
需要注意的是只讀屬性必須在給對(duì)象第一次賦值的時(shí)候進(jìn)行設(shè)置
數(shù)組類(lèi)型
簡(jiǎn)單用法
//數(shù)組內(nèi)只允許存入數(shù)值
let fibonacci: number[] = [1, 1, 2, 3, 5];
泛型用法
let fibonacci: Array<number> = [1, 1, 2, 3, 5];
接口用法(不推薦)
interface NumberArray {
[index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
需要注意的是類(lèi)數(shù)組不是數(shù)組艺配,它是一個(gè)區(qū)別于普通數(shù)組的對(duì)象
函數(shù)類(lèi)型
函數(shù)聲明
function sum(x: number, y: number): number {
return x + y;
}
函數(shù)表達(dá)式
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
};
值得注意的是我們不止要對(duì)函數(shù)做出限制,也要對(duì)承載函數(shù)的那個(gè)變量做出限制衍慎,這里使用的=>
與ES6中的=>
是兩碼事转唉。在 TypeScript 的類(lèi)型定義中,=>
用來(lái)表示函數(shù)的定義稳捆,左邊是輸入類(lèi)型赠法,需要用括號(hào)括起來(lái),右邊是輸出類(lèi)型眷柔。
使用接口定義函數(shù)
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
可選參數(shù)與默認(rèn)值
function buildName(firstName: string='ccc', lastName?: string) {
if (lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
需要注意的是:可選參數(shù)必須接在必需參數(shù)后面期虾。換句話說(shuō)原朝,可選參數(shù)后面不允許再出現(xiàn)必需參數(shù)了:
但是在 ES6 中驯嘱,我們?cè)试S給函數(shù)的參數(shù)添加默認(rèn)值,TypeScript 會(huì)將添加了默認(rèn)值的參數(shù)識(shí)別為可選參數(shù):但是這種可選參數(shù)就不受可選參數(shù)必須接在必需參數(shù)后面約束了
function buildName(firstName: string = 'Tom', lastName: string) {
return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let cat = buildName(undefined, 'Cat');