這段時間在跟著嗶哩嗶哩https://www.bilibili.com/video/BV14Z4y1u7pi?p=44&spm_id_from=333.880.my_history.page.click&vd_source=e30a43929635b513abdc7ac6a69a0e5b學(xué)習(xí)TypeScript記錄的筆記現(xiàn)在分享給大家豪诲。
1.TypeScript介紹
1.1TypeScript是什么
TypeScript(簡稱:TS)是JavaScript的超集(JS有的TS都有)。
TypeScript = Type+JavaScript(在JS基礎(chǔ)之上,為JS添加了類型支持)吃挑。
TypeScript 是微軟開發(fā)的開源編程怨言,可以在任何運行JavaScript的地方運行
1.2TypeScript為什么要為JS添加類型支持贮折?
背景:JS的類型系統(tǒng)存在"先天缺陷"弟晚,JS代碼中絕大部分錯誤都是類型錯誤(Uncaught TypeError)朋截。
問題:添加了找Bug对供、改Bug的時間位他,嚴(yán)重影響開發(fā)效率。
從變成語言的動靜來區(qū)分犁钟,TypeScript屬于靜態(tài)類型的編程語言棱诱,JS屬動態(tài)的變成語言。
靜態(tài)類型:編譯期做類型檢查涝动;動態(tài)類型:執(zhí)行期做類型檢查
代碼編譯和代碼執(zhí)行的順序:1編譯 2執(zhí)行
對JS來說:需要等待代碼真正去執(zhí)行的時候才能發(fā)現(xiàn)錯誤(晚)
對TS來說:在編譯的時候(代碼執(zhí)行前就可以發(fā)現(xiàn)錯誤)(早)
并且,配合VSCode等開發(fā)工具炬灭,TS可以提前到在編寫代碼的同時就發(fā)現(xiàn)代碼中的錯誤醋粟,減少Bug、改Bug時間重归。
1.3TypeScript相比JS的優(yōu)勢
- 更早(寫代碼的同時)發(fā)現(xiàn)錯誤米愿,減少找Bug、改Bug時間鼻吮,提升開發(fā)效率育苟。
- 程序中任何位置的代碼都有提示,隨時隨地的安全感椎木,增強了開發(fā)體驗违柏。
- 強大的類型系統(tǒng)提升了代碼的可維護(hù)性,使得重構(gòu)代碼更加容易香椎。
- 支持最新的ECMAScript語法漱竖,優(yōu)先體驗最新的語法,讓你走在前端技術(shù)的最前沿畜伐。
- TS類型判斷機(jī)制馍惹,不需要再代碼中的每個地方都演示標(biāo)注類型,讓你在享受優(yōu)勢的同時玛界,盡量降低來了成本万矾。
除此之外,Vue3源碼使用TS重寫慎框、Angular默認(rèn)支持TS良狈、React與TS完美配合,TypeScript已成為大中型前端項目的首先編程語言。
2.TypeSCript初體驗
2.1安裝編譯TS的工具包
問題:為什么要安裝編譯TS的工具包鲤脏?
回答:Node.js/瀏覽器们颜,只認(rèn)識JS代碼吕朵,不認(rèn)識TS代碼。需要將TS代碼轉(zhuǎn)化為JS代碼窥突,然后才能運行努溃。
安裝命令:npm i -g typescript
typescript包:用來編譯TS代碼的包,提供了tsc命令阻问,實現(xiàn)了TS->JS的轉(zhuǎn)化梧税。
驗證是否安裝成功:tsc -v(查看typescript的版本)。
2.2編譯并運行TS代碼
- 創(chuàng)建hello.ts文件(注意:TS文件的后綴名為.ts)称近。
- 將TS編譯為JS:在終端中輸入命令個第队,tsc hello.ts(此時,在同級目錄中會出現(xiàn)一個同名的JS文件)刨秆。
- 執(zhí)行JS代碼:在終端中輸入命令凳谦,node hello.js
說明:所有合法的JS代碼都是TS代碼,有JS基礎(chǔ)只需要學(xué)習(xí)TS類型即可
注意:由TS編譯生成的JS文件衡未,代碼中就沒有類型信息了尸执。
2.3簡化運行TS的步驟
問題描述:每次修改代碼后,都要重復(fù)執(zhí)行兩個命令缓醋,才能運行TS代碼如失,太繁瑣。
簡化方式:使用ts-node包送粱,直接在Node.js中執(zhí)行TS代碼褪贵。
安裝命令:npm i -g ts-node(ts-node包提供了ts-node命令)。
使用方式:ts-node hello.ts抗俄。(遇到錯誤了:在安裝完ts-node之后執(zhí)行這個使用命令會報錯脆丁,原因是缺少安裝東西,執(zhí)行命令 npm install -g tslib @types/node)
解釋:ts-node命令在內(nèi)部偷偷的將TS->JS橄镜,然后偎快,再運行JS代碼。
3.TypeScript常用類型
概述
TypeScript是JS的超集洽胶,TS提供了JS的所有功能晒夹,并且額外的增加了:類型系統(tǒng)。
所有的JS代碼都是TS代碼
JS有類型(比如:number/string等) 姊氓,但是JS不會檢查變量的類型是否發(fā)生變化丐怯。而TS會檢查。TypeScript類型系統(tǒng)的主要優(yōu)勢:可以顯示標(biāo)記出代碼中的意外行為翔横,從而降低了發(fā)生錯誤的可能性读跷。
3.1.類型注解
實例代碼:
let age:number = 18
說明:代碼中的:number就是類型注解。
作用:為變量添加類型約束禾唁,比如效览,上述代碼中无切,約定變量age的類型為number(數(shù)值類型)。
解釋:約定了什么類型丐枉,就只能給變量賦值該類型的值哆键,否則,就會報錯瘦锹。
3.2常用基礎(chǔ)類型概述
可以將TS中的常用基礎(chǔ)類型細(xì)分為兩類:
-
JS已有類型
原始類型:number/string/boolean/null/undefined/symbol
對象類型:Object(包括籍嘹,數(shù)組、對象弯院、函數(shù)等對象)辱士。
-
TS新增類型
聯(lián)合類型、自定義類型(類型別名)听绳、接口颂碘、元祖、字面量類型辫红、枚舉凭涂、void、any等
3.3原始類型
1.原始類型:number/string/boolean/null/undefined/symbol
特點:簡單贴妻。這些類型,完全按照J(rèn)S中類型的名稱來書寫
let age: number = 18
let myName: string = "啦啦啦"
let isLoading: boolean = false
let a: null = null
let b: undefined = undefined
let s: symbol = Symbol()
3.4數(shù)組類型
2.對象類型:Object(包括蝙斜,數(shù)組名惩、對象、函數(shù)等對象)孕荠。
特點:對象類型娩鹉,在TS中更加細(xì)化,每個具體的對象都有自己的類型語法稚伍。
數(shù)組類型的兩種寫法:(推薦使用number[]寫法)
let numbers: number[] = [1,2,3]
let string: Array<string> = ["a","b","c"]
需求:數(shù)組中既有number類型弯予,又有string類型,這個數(shù)組的類型應(yīng)該如何寫个曙?
let arr: (number | string)[] = [1,'a','c',2]
解釋:| (豎線) 在TS中叫做聯(lián)合類型(由兩個或多個其他類型組成的類型锈嫩,表示可以是這些類型中的任意一種)。
注意:這是TS中聯(lián)合類型的語法垦搬,只有一根豎線呼寸,不要與JS中的或(||)混淆了。
3.5類型別名
類型別名:(自定義類型):為任意類型起別名猴贰。
使用場景:當(dāng)同一類型(復(fù)雜)被多次使用時对雪,可以通過類型別名,簡化該類型的使用米绕。
type CustomArray = (number | string)[]
let arr1: CustomArray = [1,'a',3,'b']
let arr2: CustomArray = ['x','y',6,7]
解釋:
使用type關(guān)鍵字來創(chuàng)建類型別名瑟捣。
類型別名(比如馋艺,此處的CustomArray),可以是任意合法的變量名稱迈套。
創(chuàng)建類型別名后捐祠,直接使用該類型別名作為變量的類型注解即可。
3.6 函數(shù)類型
函數(shù)的類型實際上指的是:函數(shù)參數(shù)和返回值的類型交汤。
為函數(shù)指定類型的兩種方式:1單獨指定參數(shù)雏赦、返回值的類型 2同時指定參數(shù)、返回值的類型
3.6.1.單獨指定參數(shù)芙扎、返回值的類型:
function add(num1: number,num2: number):number{
return num1 + num2
}
// 函數(shù)表達(dá)式的方式
const add = (num1: number,num2: number):number =>{
return num1 + num2
}
3.6.2.同時指定參數(shù)星岗、返回值的類型:
type CustomArray = (number | string)[]
let arr1: CustomArray = [1,'a',3,'b']
let arr2: CustomArray = ['x','y',6,7]
解釋:當(dāng)函數(shù)作為表達(dá)式時,可以通過類似箭頭函數(shù)形式的語法來為函數(shù)添加類型戒洼。
注意:這種形式只適用于函數(shù)表達(dá)式俏橘。
3.6.3.void類型
如果函數(shù)沒有返回值,那么圈浇,函數(shù)返回值類型為:void寥掐。
function greet(name: string): void{
console.log("hello")
}
3.6.4.可選參數(shù)
使用函數(shù)實現(xiàn)某個功能時,參數(shù)可以傳也可以不傳磷蜀。這種情況下召耘,在給函數(shù)參數(shù)指定類型時,就用到可選參數(shù)了褐隆。比如污它,數(shù)組的slice方法,可以slice()也可以slice(1)還可以slice(1,3)庶弃。
function mySlice(start?:number,end?:number):void{
console.log('起始索引:',start,'結(jié)束索引:',end)
}
可選參數(shù):在可傳可不傳的參數(shù)名稱后面添加衫贬?(問號)。
注意:可選參數(shù)只能出現(xiàn)在參數(shù)列表后面歇攻,也就是說可選參數(shù)后面不能再出現(xiàn)必選參數(shù)固惯。
3.7對象類型
JS中的對象是由屬性和方法構(gòu)成的,而TS中對象的類型就是再描述對象的結(jié)構(gòu)(有什么類型的屬性和方法)缴守。
對象類型的寫法:
let person:{name:string;age:number;sayHi():void;greet(name:string):void}={
name:'jack',
age:19,
sayHi(){},
green(name){}
}
let person:{//多行的話可以省略;(分號)
name:string
age:number
sayHi():void
sayHi1:()=>void //箭頭函數(shù)的寫法
greet(name:string):void
}={
name:'jack',
age:19,
sayHi(){},
sayHi1(){},
green(name){}
}
解釋:
直接使用{}來描述對象結(jié)構(gòu)葬毫。屬性采用屬性名:類型的形式;方法采用方法名():返回值類型的形式斧散。
如果方法有參數(shù)供常,就在方法名后面的小括號中指定參數(shù)類型(比如:greet(name:string):void)。
在一行代碼中指定對象的對個屬性類型時鸡捐,使用栈暇;(分號)來分隔。
如果一行代碼只指定一個屬性類型(通過換行來分隔多個屬性類型)箍镜,可以去掉源祈;(分號)煎源。
方法的類型也可以使用箭頭函數(shù)形式(比如:{sayHi:()=>void})。
對象的屬性或方法香缺,也可以是可選的手销,此時就用到可選屬性了
比如,我們再使用axios({...})時图张,如果發(fā)送GET請求锋拖,method屬性就可以省略。
function myAxios(config:{url:string;method?:string}){
console.log(config)
}
可選屬性的語法與函數(shù)可選參數(shù)的語法一致祸轮,都使用?(問號)來表示兽埃。
3.8接口
當(dāng)一個對象類型被多次使用時,一般會使用接口(interface)來描述對象的類型适袜,達(dá)到服用的目的柄错。
interface IPerson{
name:string
age:number
sayHi():void
}
let person:IPerson={
name:'jack',
age:19,
sayHi(){}
}
解釋:
1.使用interface關(guān)鍵詞來聲明接口。
2.接口名稱(比如苦酱,此處的IPerson)售貌,可以是任意合法的變量名稱。
3.聲明接口后疫萤,直接使用接口名稱作為變量的類型颂跨。
4.因為每一行只有一個屬性類型,因此扯饶,屬性類型后沒有毫捣;(分號)。
interface(接口)和type(類型別名)的對比:
相同點:都可以給對象指定類型帝际。
不同點:1.接口,只能為對象指定類型饶辙。2.類型別名蹲诀,不僅可以為對象指定類型,實際上可以為任意類型指定別名弃揽。
interface IPerson {
name:string
age:number
sayHi():void
}
type IPerson = {
name:string
age:number
sayHi():void
}
type NumStr = number | string
接口之間的繼承
如果兩個接口之間有相同的屬性或方法脯爪,可以將公共的屬性或方法抽離出來,通過繼承來實現(xiàn)復(fù)用矿微。
比如痕慢,這兩個接口都有x、y兩個屬性涌矢,重復(fù)寫兩次掖举,可以,但是很繁瑣娜庇。
interface Point2D{x:number;y:number}
interface Point3D{x:number;y:number;z:number}
更好的方式:
interface Point2D{x:number;y:number}
interface Point3D extends Point2D {z:number}
解釋:
使用extends(繼承)關(guān)鍵字實現(xiàn)接口Point3D繼承Point2D塔次。
繼承后方篮,Point3D就有了Point2D的所有屬性和方法(此時,Point3D同時有x励负、y藕溅、z三個屬性)。
3.9元組
場景:在地圖中继榆,使用經(jīng)緯度坐標(biāo)來標(biāo)記位置信息巾表。
可以使用數(shù)組來記錄坐標(biāo),那么略吨,該數(shù)組中只有兩個元素集币,并且這兩個元素都是數(shù)值類型。
let position: number[] = [39.5427, 116.2317]
使用number[]的缺點:不嚴(yán)謹(jǐn)晋南,因為該類型的數(shù)組中可以出現(xiàn)任意多個數(shù)字惠猿。
更改的方式:元組(Tuple)。
元組類型是另一種類型的數(shù)組负间。它確切地知道包含多少元素偶妖,以及特定索引對應(yīng)的類型。
let position: [number, number] = [39.5427, 116.2317]
解釋:
元組類型可以確切地標(biāo)記處有多少元素政溃,以及每個元素的類型趾访。
該示例中,元素有兩個元素董虱,每個元素的類型都是number
3.10類型推論
在TS中扼鞋,某些沒有明確指出類型的地方,TS的類型推論機(jī)制會幫助提供類型愤诱。
換句話說:由于類型推論的存在云头,這些地方,類型注解可以省略不寫淫半!
發(fā)生類型推論的2中常見場景:1聲明變量并初始化時 2決定函數(shù)返回值時溃槐。
let age = 18
//鼠標(biāo)移入變量名age TS自動推斷出變量age為number類型
function add(num1:number,num2:number){return num1 + num2}
//TS會自動提示返回值類型時number
注意:這兩種情況下,類型注釋可以省略不寫!
推薦:能省略類型注解的地方就省略(不是偷懶科吭,充分利用TS類型推論的能力昏滴,提升開發(fā)效率)。
技巧:如果不知道類型对人,可以通過鼠標(biāo)放在變量名稱上谣殊,利用VSCode的提示來查看類型。
3.11類型斷言
有時候你會比TS更明確一個值的類型牺弄,此時姻几,可以使用類型斷言來指定更具體的類型
比如
<a id="link">百度</a>
<script>
const aLink = document.getElementById('link');
//鼠標(biāo)移動上去 顯示const aLink: HTMLElement
</script>
注意:getElementById方法返回值的類型時HTMLElement,該類型只包含所有標(biāo)簽公共的屬性或方法,不包含a標(biāo)簽特有href等屬性鲜棠。
因此肌厨,這個類型太寬泛(不具體),無法操作href等a標(biāo)簽特有的屬性或方法豁陆。
解決方式:這種情況下就需要使用類型斷言指定更加具體的類型柑爸。
使用類型斷言:
<a id="link">百度</a>
<script>
const aLink = document.getElementById('link') as HTMLAnchorElement;
//鼠標(biāo)移動上去 顯示const aLink: HTMLElement
</script>
解釋:
使用as關(guān)鍵字實現(xiàn)類型斷言。
關(guān)鍵字as后面的類型時一個更加具體的類型(HTMLAnchorElement是HTMLElement的子類型)盒音。
通過類型斷言表鳍,aLink的類型變得更加具體,這樣就可以訪問a標(biāo)簽特有的屬性或方法了祥诽。
另一種語法譬圣,使用<>語法,這種語法形式不常用知道即可:
const aLink = <HTMLAnchorElement>document.getElementById('link')雄坪;
// ***** 這個方法不是很常用 在寫react中這個寫法跟jsx語法沖突 不能使用厘熟。
技巧:在瀏覽器控制臺,通過console.dir()打印DOM元素维哈,在屬性列表的后面绳姨,即可看到該元素的類型。
3.12字面量類型
思考一下一下代碼阔挠,另個變量的類型分別是什么飘庄?
let str1 = "hello"
const str2 = "hello"
通過TS類型推論機(jī)制,可以得到答案:
變量str1的類型為string购撼。
變量str2的類型為'hello'跪削。
解釋:
str1是一個變量(let),它的值可以是任意字符串迂求,所以類型為:string怖侦。
str2是一個常量密似,它的值不能變化只能是'hello'宏娄,所以际插,它的類型為'hello'。
注意:此處的"hello"谐腰,就是一個字面量類型。也就是說某個特定的字符串也可以作為TS中的類型涩盾。除字符串外十气,任意的JS字面量(比如,對象春霍,數(shù)字等)都可以作為類型使用砸西。
使用模式:字面量類型配合聯(lián)合類型一起使用。
使用場景:用來表示一組明確地可選值列表。
比如芹枷,在貪吃蛇游戲中衅疙,游戲的方向的可選值只能是上下左右中的任意一個。
function changDirection(direction:'up' | 'down' | 'left' | 'right'){
console.log(direction)
}
解釋:參數(shù)direction的值只能是up/down/left/right中的任意一個鸳慈。
優(yōu)勢:相比于string類型饱溢,使用字面量類型更加精確、嚴(yán)謹(jǐn)走芋。
3.13枚舉
枚舉的功能類似于字面量+聯(lián)合類型組合的功能绩郎,也可以表示一組明確的可選值。
枚舉:定義一組命名常量翁逞。它描述一個值肋杖。該值可以是這些命名常量中的一個。
enum Direction {up,Down,Left,Right}
function changeDirection(direction:Direction){
console.log(direction)
}
解釋:
使用enum關(guān)鍵字定義枚舉挖函。
約定枚舉名稱状植、枚舉中的值以大寫字母開頭。
枚舉中的多個值之間通過怨喘,(逗號)分隔津畸。
定義好枚舉后,直接使用枚舉名稱作為類型注解哲思。
注意:參數(shù)direction的類型為枚舉Direction洼畅,那么,實參的值就應(yīng)該是枚舉Direction成員的任意一個棚赔。
訪問枚舉成員:
enum Direction {Up,Down,Left,Right}
function changeDirection(direction:Direction){
console.log(direction)
}
changeDirection(Direction.Up)
解釋:類似于JS中的對象帝簇,直接通過點(.)語法訪問枚舉成員。
問題:我們把枚舉成員作為了函數(shù)的實參靠益,他的值是什么呢丧肴?
changeDirection(Direction.Up);
// 鼠標(biāo)移動上去顯示(enum atemember)Direction.Up = 0
解釋:通過將鼠標(biāo)移入Direction.Up,可以看到枚舉成員Up的值為0胧后。
注意:枚舉成員是有值的芋浮,默認(rèn)為:從0開始自增的數(shù)值。
我們把壳快,枚舉成員的值為數(shù)字的枚舉纸巷,稱為:數(shù)字枚舉。
當(dāng)然眶痰,也可以給枚舉中的成員初始化值瘤旨。
// Down -> 11, Left -> 12 ,Right -> 13
enum Direction { Up =10, Down, Left, Right }
enum Direction { Up = 2, Down = 4, Left = 8, Right = 16 }
3.13.1 字符串枚舉
字符串枚舉:枚舉成員的值是字符串。
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT'
}
注意:字符串枚舉沒有自增長行為竖伯,因此存哲,字符串枚舉的每個成員必須有初始值因宇。
3.13.2 枚舉特性和實現(xiàn)原理
枚舉是TS為數(shù)不多的非JavaScript類型級擴(kuò)展(不僅僅是類型)的特性之一。
因為:其他類型僅僅被當(dāng)做類型祟偷,而枚舉不僅僅作用類型察滑,還提供值(枚舉成員都是有值的)。
也就是說修肠,其他的類型會在編譯為JS代碼時自動移除贺辰。但是,枚舉類型會被編譯為JS代碼氛赐!
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT'
}
//===>編譯后
var Direction;
(function(Direction){
Direction["Up"] = "UP":
Direction["Down"] = "DOWN":
Direction["Left"] = "LEFT":
Direction["Right"] = "RIGHT":
})(Direction || (Direction = {}))
說明:枚舉與前面講到的字面量類型+聯(lián)合類型組合的功能類似魂爪,都用來表示一組明確的可選值列表。
一般情況下艰管,推薦使用字面量類型+聯(lián)合類型組合的方式滓侍,因為相比枚舉,這種方式更加直觀牲芋、簡潔撩笆、高效。
3.14 any類型
原則:不推薦使用any 缸浦!這回讓TypeScript變?yōu)?AnyScript"(失去TS類型保護(hù)的優(yōu)勢)夕冲。
因為當(dāng)值得類型為any時,可以對該值進(jìn)行任意操作裂逐,并且不會有代碼提示歹鱼。
let obj:any ={x:0}
obj.bar=100
obj()
const n:number = obj
解釋:以上操作都不會有任何類型錯誤提示,即使可能存在錯誤卜高!
盡可能的避免使用any類型弥姻,除非臨時使用any來"避免"書寫很長、很復(fù)雜的類型掺涛!
其他隱式具有any類型的情況:
聲明變量不提供類型也不提供默認(rèn)值
函數(shù)參數(shù)不添加類型
注意:因為不推薦使用any庭敦,所以,這兩種情況下都應(yīng)該提供類型薪缆!
3.15typeof
中所周知秧廉,JS中提供了typeof操作父,用來在JS中獲取數(shù)據(jù)的類型拣帽。
console.log(typeof "hello world")
實際上疼电,ts也提供了typeof操作符:可以再類型上下文中引用變量或?qū)傩缘念愋停愋筒樵儯?/p>
使用場景:根據(jù)已有變量的值,獲取該值得類型减拭,來簡化類型書寫澜沟。
let p={x:1,y:2}
function formatPoint(point:{x:number;y:number}){}
formatPoint(p)
function formatPoint(point:type p){}
解釋:
使用typeof操作符來獲取變量p的類型,結(jié)果與第一種(對象字面量形式的類型)相同峡谊。
typeof出現(xiàn)在類型注解的位置(參數(shù)名稱的冒號后面)所處的環(huán)境就在類型上下文(區(qū)別于JS代碼)。
注意:typeof只能用來查詢變量或?qū)傩缘念愋停瑹o法查詢其他形式的類型(比如函數(shù)調(diào)用的類型)既们。