前言
現(xiàn)在TypeScript越來越火托呕,咱也趕一下潮流充甚,開始學習一下TypeScript演熟,在學習的同時做筆記記錄鞭执,希望可以共同學習,在未來的程序生涯中可以使用TypeScript來進行開發(fā)芒粹。
TypeScript是什么兄纺?
TypeScript 是 JavaScript 的一個超集,主要提供了類型系統(tǒng)和對 ES6 的支持化漆,因為JavaScript是弱類型語言估脆,我們在開發(fā)的時候,很容易會因為數據類型的原因造成一些不明不白的錯誤获三,所以旁蔼,在TypeScript中,對類型的檢測是極為嚴格的疙教。
TypeScript的優(yōu)勢
在這里我借用阮一峰大神的文章來說一下TypeScript的優(yōu)勢棺聊。
-
TypeScript 增加了代碼的可讀性和可維護性;
- 類型系統(tǒng)實際上是最好的文檔贞谓,大部分的函數看看類型的定義就可以知道如何使用了
- 可以在編譯階段就發(fā)現(xiàn)大部分錯誤限佩,這總比在運行時候出錯好
- 增強了編輯器和 IDE 的功能,包括代碼補全裸弦、接口提示祟同、跳轉到定義、重構等
-
TypeScript 非常包容理疙;
- TypeScript 是 JavaScript 的超集晕城,
.js
文件可以直接重命名為.ts
即可 - 即使不顯式的定義類型,也能夠自動做出類型推論
- 可以定義從簡單到復雜的幾乎一切類型
- 即使 TypeScript 編譯報錯窖贤,也可以生成 JavaScript 文件
- 兼容第三方庫砖顷,即使第三方庫不是用 TypeScript 寫的,也可以編寫單獨的類型文件供 TypeScript 讀取
- TypeScript 是 JavaScript 的超集晕城,
-
TypeScript 擁有活躍的社區(qū)赃梧;
- 大部分第三方庫都有提供給 TypeScript 的類型定義文件
- Google 開發(fā)的 Angular2 就是使用 TypeScript 編寫的
- TypeScript 擁抱了 ES6 規(guī)范延赌,也支持部分 ESNext 草案的規(guī)范
TypeScript的缺點
- 無非就是難學了一點沸毁,無所謂啦,反正再難學還是要學的!自己選的路抡句,跪著也要走下去。
寫在前邊
首先一定要從JavaScript的弱類型思想中走出來旧噪,在TypeScript中菌湃,保證在大部分時候都要給數據定義類型。
其次一定要堅持巷折,堅持焕济,堅持。
那就先從基礎開始吧盔几!
安裝使用
- 首先全局安裝typescript
npm install typescript -g
- 當全局安裝后晴弃,我們就可以在全局下使用
tsc
指令了
先通過tsc -v
查看一下當前的TypeScript的版本號,順便看一下有沒有安裝成功逊拍。tsc -v
- 接著新建一個文件夾上鞠,新建一個
.ts
文件,例如:index.ts
;
在使用TypeScript時芯丧,我們使用.ts
為后綴的文件芍阎,如果是使用React的時候,我們默認使用.tsx
為后綴的文件缨恒。它們分別對應的是.js
和.jsx
文件谴咸。 - 在
index.ts
文件中轮听,寫入如下代碼function sayHello(person: string) { return 'Hello' + person; } let person = [1, 2, 3]; sayHello(person);
- 打開命令提示符,通過如下指令編譯TypeScript文件
tsc index.ts
- 執(zhí)行會發(fā)現(xiàn)命令提示符報錯
index.ts:5:10 - error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'string'
岭佳,因為我們給函數的參數定義成為string類型血巍,而我們傳入的是一個數組,所以會報錯珊随。 - 但是雖然報錯了述寡,依舊生成了
index.js
文件,這是因為TypeScript文件就算編譯出錯也依舊會編譯成js文件叶洞,畢竟這點錯誤在咱們的JavaScript里邊不算什么鲫凶。 - 接著修改我們的
index.ts
文件function sayHello(person: string) { return 'Hello' + person; } let person: string = '郝晨光'; sayHello(person);
- 再次執(zhí)行
tsc index.ts
指令 - 這次命令提示符沒有任何的錯誤信息,并且可以看到生成的
index.js
文件衩辟。
基本類型
對于基本類型螟炫,直接定義類型即可。定義好就必須指定類型艺晴,不可以變成其它類型不恭。
- 定義布爾類型的值
// 布爾值 let isDone: boolean = true;
- 定義數字類型的值
// 數字 let count: number = 1;
- 定義字符串類型的值
// 字符串 let str:string = 'typescript';
- 定義空值
空值是typescript中新引入的一種基本類型,可以用 void 表示沒有任何返回值的函數财饥。
或者聲明一個空值,但是這樣毫無意義钥星,因為只能被賦值為undefined和null沾瓦。function alertName(): void { alert('郝晨光加油换吧!') }
let myVoid1: void = undefined; let myVoid2: void = null;
- 定義null和undefined
需要注意的是,null和undefined可以被賦予任何類型谦炒,但是void的空值不能被賦予其他類型贯莺。// null let nullSet: null = null; // undefined let undeSet: undefined = undefined;
let unsetNumber: number = null; let unsetString: string = undefined;
- 任意類型
我們都非常熟悉JavaScript,在JavaScript中宁改,我們的變量是可以隨時轉換數據類型的缕探,但是在TypeScript中,對于定義好的基本數據類型是不可以的还蹲!那我們如何實現(xiàn)一個不一定是什么數據類型的值呢爹耗?就該使用任意類型了。// 任意類型 // 對于任意類型谜喊,可以在賦值后修改數據類型潭兽。 let myAny: any = 'string'; myAny = 123; // 變量在聲明的時候沒有指定類型,并且沒有賦值斗遏,自動編譯為 any 類型 let anyThing; anyThing = '未指定類型并且未賦值山卦,自動編譯為 any 類型'; anyThing = 1234;
類型推斷
了解了基本數據類型,接下來就應該先了解一下TypeScript的類型推斷诵次,在TypeScript中账蓉,如果你沒有給(變量/數據)指定一個數據類型枚碗,分為兩種情況,
- 一種是定義未賦值铸本,就是我們在上邊的任意類型中提到的肮雨,它會自動聲明成為any類型。
- 而如果我們在定義(變量/數據)的時候归敬,給它賦值,但是不給它指定類型的話鄙早,TypeScript就會進行類型推斷汪茧。
在上邊的案例中弥虐,在定義stringThing變量定義時扩灯,給它賦值成為string,經過TypeScript的類型推斷后霜瘪,它會被設置成為string數據類型珠插,而當我們給它賦值成為number類型時,TypeScript就會進行報錯颖对。// 但是如果變量在聲明是賦值了,但是沒有指定類型 // 經過類型推斷限番,它應該是賦值時候的數據類型,即為string舱污。 let stringThing = '未指定類型,但是賦值為string'; stringThing = 1234; // 報錯
聯(lián)合類型
我們在實際開發(fā)中經常會遇到這樣的問題捻撑,一個參數,它既有可能是string類型缤底,又有可能是number類型顾患,那這種情況,如果我們用TypeScript應該怎么定義呢个唧?肯定不可能使用any吧江解,那樣的話,我們還可以設置其他類型的值徙歼。所以犁河,就出現(xiàn)了聯(lián)合類型。
// 聯(lián)合類型(多個類型)
let numString: string | number = '一開始是string';
numString = 123456789; // 可以被賦值為number類型
numString = true; // 報錯魄梯,不可以是boolean類型呼股。
但是,針對聯(lián)合類型画恰,只能使用它們之間公共的方法彭谁,不能使用其中一個特有的方法。例如:
// 由于number是沒有l(wèi)ength屬性的允扇,所以會報錯
function getLength(some: string | number): number {
return some.length;
}
訪問number和string的公共屬性沒有任何問題缠局,不會報錯则奥。
function getString(some: string | number): string {
return some.toString();
}
聯(lián)合類型會在被賦值的時候推斷出一個類型,并監(jiān)聽除當前數據類型以外的錯誤狭园。
let myName: string | number;
myName = '郝晨光';
// 此時是字符串類型读处,所以調用length屬性沒有任何問題
console.log(myName.length); // 3
myName = 123;
// 此時是number類型,沒有l(wèi)enght屬性唱矛,所以會報錯
console.log(myName); // error TS2339: Property 'length' does not exist on type 'number'.
對象的類型
在ts中罚舱,通過接口(interface)來定義對象的類型;
-
接口定義了對象的值的類型绎谦,并且定義了對象的參數管闷,多一個參數少一個參數都不可以。
interface Person { name: string, age: number, sex: string } let person: Person = { name: '郝晨光', age: 24, sex: '男' };
-
當我們的對象有一些屬性不是必須的時候窃肠,可以通過?來定義包个,?表示屬性是可選的。
interface People { name: string, age: number, sex?: string } let girl: People = { name: 'girl', age: 20 };
-
當我們的對象有一些未知的屬性時冤留,可以通過[propName]來定義
interface Student { name: string, age?: number, [propName: string]: string | number } let student: Student = { name: '學生', age: 20, className: 'A班' };
- 如果設置了propName的話碧囊,可選的值(帶?的值),就必須是propName的指定值的子類型
- 例如any纤怒,所有類型都是它的子類型糯而,或者通過聯(lián)合類型來指定
- 在上邊的案例中,如果我只給propName指定數據類型為string的話泊窘,TypeScript就會報錯歧蒋,因為age屬性需要的是number類型的值。
-
我們還可以給對象設置只讀的屬性州既。
// 只讀屬性 // 通過 readonly 屬性來設置屬性是只讀的 interface Teacher { readonly id: number, name: string, age?: number, [propName: string]: any } let teacher: Teacher = { id: 123456, name: '郝晨光', age: 24, className: 'A班' }; console.log(teacher.id); teacher.id = 1231546; // 報錯谜洽,因為是只讀的,不能修改
數組的類型
在TypeScript中定義數組的方式有很多
- 類型 + 方括號
let arr1: number[] = [1, 2, 3]; // 如果出現(xiàn)非number的值吴叶,就會報錯 arr1 = [1, 2, '1', 3]; // 報錯 arr1.push(10); // 正常 arr1.push('10'); // 報錯
- 數組泛型
let arr2: Array<number> = [1, 2, 3]; arr2 = [1, 2, '1', 3]; // 報錯; arr2.push(10); //正常 arr2.push('10'); // 報錯
- 使用接口interface定義
interface NumberArray { [index: number]: number // 定義數據是number類型 push(number: number): void; // 定義push方法接收number類型的值阐虚,并返回空值 } let arr3: NumberArray = [1, 2, 3]; arr3 = [1, 2, '1', 3]; // 報錯; arr3.push(10); // 正常 arr3.push('10'); // 報錯
- 使用any定義數組
// 數組中允許出現(xiàn)任意類型的值 let arr4: any[] = [1, '2', new Date(), 3];
- 類數組
類數組不能通過數組的方式定義,每一個類數組都有它對應的內置對象arguments ==> IArguments NodeList ==> NodeList HTMLCollection ==> HTMLCollection ···
函數的類型
在JavaScript中蚌卤,定義函數有兩種方式实束,一種是函數聲明式,另一種是函數表達式逊彭。
在函數定義之后咸灿,輸入多余的(或者少于要求的)參數,是不被允許的侮叮。
- 函數聲明式
function fn(x: number, y: number): number { return x + y; }
- 函數表達式
注意:這樣聲明對于左邊的變量來說避矢,并沒有任何數據指定,雖然不會報錯,但是是不嚴謹的
所以我們應該這樣定義审胸。let fn2 = function(x: number, y: number): number { return x + y; };
需要注意的是TypeScript中亥宿,用在此處的 => 與 ES6中的箭頭函數是沒有任何關系的,此處只是為了指定返回值的數據類型砂沛。let fn3: (x: number, y: number) => number = function(x: number, y: number): number { return x + y; };
- 使用接口interface定義函數
interface Fun { (x: number, y: number): number } // 此時可以不指定右邊的函數的返回值的類型烫扼,因為在接口中定義了 let fn4: Fun = function(x: number, y: number) { return x + y; };
- 可選參數
需要注意的是,可選參數必須出現(xiàn)在最后碍庵,不能在可選參數之后又出現(xiàn)必須參數映企。function fn5(firstName: string, lastName?: string): string { return firstName + ' ' + lastName; }
下面的案例會報錯!
函數出現(xiàn)多個可選參數function fn6(x?: number,y: number): number { return x + y; }
// 出現(xiàn)多個可選參數 function fn7(x: number,y?: number, z?: number): number { return x + y + z; }
- 參數默認值
當定義了默認值時静浴,可選參數將不會在受限制堰氓,可以出現(xiàn)在必須參數前邊,調用時直接傳入null或者undefined即可马绝。function fn8(x: number = 5,y: number):number { return x + y; } fn8(null,10); // 15 fn8(10, 20); // 30
- 剩余參數
在ES6中豆赏,可以通過擴展運算符來接收剩余的參數挣菲,剩余參數其實就是一個數組富稻,所以可以通過any[]或者Array<any>等等方式定義類型。function fn9(arr: any[], ...args: any[]): Array<any> { args.forEach(item => { arr.push(item); }); return arr; }
- 函數重載
重載就是指函數在接收不同類型的參數或者不同數量的參數時白胀,做出不同的處理椭赋,返回不同的結果。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(x === 'string'){ return x.split('').reverse().join(''); } } reverse(123456); reverse('123456');
本文參考:TypeScript入門教程 - 阮一峰
如果本文對您有幫助或杠,可以看看本人的其他文章:
簡單實現(xiàn)Vue響應式原理@郝晨光
前端常見面試題(十六)@郝晨光
前端常見面試題(十五)@郝晨光