1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        TypeScript上手指南

        共 27996字,需瀏覽 56分鐘

         ·

        2021-08-27 09:56

        前言

        ?

        哈嘍,我是樹醬,今天分享一篇蛙人的typescript指南,自從vue3、還有社區(qū)一些開源工具、組件庫等都開始基于typescript開發(fā),其自帶的"可選的靜態(tài)類型系統(tǒng)",可以使得當我們在應用程序運行之前,通過編譯器就可以顯示有關任何潛在問題的警告

        ?

        一、為什么要用TypeScript

        TypeScript可以讓我們開發(fā)中避免一些類型或者一些不是我們預期希望的代碼結(jié)果錯誤。xxx is not defined 我們都知道JavaScript錯誤是在運行中才拋出的,但是TypeScript錯誤直接是在編輯器里告知我們的,這極大的提升了開發(fā)效率,也不用花大量的時間去寫單測,同時也避免了大量的時間排查Bug

        二、TypeScript優(yōu)缺點

        優(yōu)點

        • 一般我們在前后端聯(lián)調(diào)時,都要去看接口文檔上的字段類型,而TypeScript會自動幫我們識別當前的類型。節(jié)省了我們?nèi)タ?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">文檔或者network時間。這叫做類型推導(待會我們會講到)

        • 友好地在編輯器里提示錯誤,避免代碼在運行時類型隱式轉(zhuǎn)換踩坑。

        缺點

        • 有一定的學習成本,TypeScript中有幾種類型概念,interface接口、class類、enum枚舉、generics泛型等這些需要我們花時間學習。

        • 可能和一些插件庫結(jié)合的不是很完美

        三、TypeScript運行流程及JavaScript代碼運行流程

        「1. JavaScript運行流程如下,依賴NodeJs環(huán)境和瀏覽器環(huán)境」

        • JavaScript代碼轉(zhuǎn)換為JavaScript-AST
        • AST代碼轉(zhuǎn)換為字節(jié)碼
        • 運算時計算字節(jié)碼

        「2. TypeScript運行流程,以下操作均為TSC操作,三步執(zhí)行完繼續(xù)同上操作,讓瀏覽器解析」

        • TypeScript代碼編譯為 TypeScript-AST
        • 檢查AST代碼上類型檢查
        • 類型檢查后,編譯為JavaScript代碼
        • JavaScript代碼轉(zhuǎn)換為JavaScript-AST
        • AST代碼轉(zhuǎn)換為字節(jié)碼
        • 運算時計算字節(jié)碼

        四、TypeScript和JavaScript區(qū)別

        只有搞懂了二者的區(qū)別,我們才可以更好的理解TypeScript

        類型系統(tǒng)特性JavaScriptTypeScript
        類型是如何綁定?動態(tài)靜態(tài)
        是否存在類型隱式轉(zhuǎn)換?
        何時檢查類型?運行時編譯時
        何時報告錯誤運行時編譯時

        類型綁定

        「JavaScript」

        JavaScript動態(tài)綁定類型,只有運行程序才能知道類型,在程序運行之前JavaScript對類型一無所知

        「TypeScript」

        TypeScript是在程序運行前(也就是編譯時)就會知道當前是什么類型。當然如果該變量沒有定義類型,那么TypeScript會自動類型推導出來。

        類型轉(zhuǎn)換

        「JavaScript」

        比如在JavaScript1 + true這樣一個代碼片段,JavaScript存在隱式轉(zhuǎn)換,這時true會變成number類型number(true)和1相加。

        「TypeScript」

        TypeScript中,1+true這樣的代碼會在TypeScript中報錯,提示number類型不能和boolean類型進行運算。

        何時檢查類型

        「JavaScript」

        JavaScript中只有在程序運行時才能檢查類型。類型也會存在隱式轉(zhuǎn)換,很坑。

        「TypeScript」

        TypeScript中,在編譯時就會檢查類型,如果和預期的類型不符合直接會在編輯器里報錯、爆紅

        何時報告錯誤

        「JavaScript」

        JavaScript只有在程序執(zhí)行時才能拋出異常,JavaScript存在隱式轉(zhuǎn)換,等我們程序執(zhí)行時才能真正的知道代碼類型是否是預期的類型,代碼是不是有效。

        「TypeScript」

        TypeScript中,當你在編輯器寫代碼時,如有錯誤則會直接拋出異常,極大得提高了效率,也是方便。

        五、TypeScript總共圍繞兩種模式展開

        顯式注解類型

        舉個栗子

        let name: string = "前端娛樂圈";

        let age: number = 38;

        let hobby: string[] = ["write code""玩游戲"]

        顯式注解類型就是,聲明變量時定義上類型(官方話語就是「聲明時帶上注解」),讓我們一看就明白,哦~,這個name是一個string類型。

        推導類型

        舉個栗子

        let name = "前端娛樂圈"// 是一個string類型

        let age = 38;  // 是一個number類型

        let hobby = ["write code""玩游戲"// 是一個string數(shù)組類型

        推導類型就是去掉顯示注解,系統(tǒng)自動會識別當前值是一個什么類型的。

        六、安裝TypeScript && 運行

        typescript

        全局安裝typescript環(huán)境。

        npm i -g typescript

        可是這只是安裝了typescript,那我們怎么運行.ts文件呢,安裝完typescript我們就可以執(zhí)行tsc命令。

        如:我們的文件叫做index.ts,直接在命令行執(zhí)行tsc index.ts即可。然后就可以看到在目錄下編譯出來一個index.js,這就是tsc編譯完的結(jié)果。

        「index.ts」

        const userName: string = "前端娛樂圈" 

        運行tsc index.ts,你可以看見在index.ts的同級下又生成一個index.js,如下就是編譯的結(jié)果文件index.js。

        var userName = "前端娛樂圈"

        上面我們知道了運行tsc命令就可以編譯生成一個文件,有的小伙伴覺得這樣太麻煩了,每次運行只是編譯出來一個文件還不是運行,還得用node index.js才可以運行。不急我們接著往下看

        ts-node

        我們來看一下這個插件ts-node,這個插件可以直接運行.ts文件,并且也不會編譯出來.js文件。

        npm i ts-node

        // 運行 ts-node index.ts

        講到這里我們了解了「為什么要用TypeScript」和它的「優(yōu)缺點」以及它的「運行工作方式」。

        那么接下來步入TypeScript基礎知識的海洋啦~,follow me。

        感覺有幫助的小伙伴可以關注一下:「前端娛樂圈」 公眾號,謝謝啦~,每天更新一篇小技巧

        七、基礎知識

        1. 基礎靜態(tài)類型

        TypeScript中基礎類型跟我們JavScript中基礎類型是一樣的。只是有各別是Ts里面新出的。

        1. number

        const count: number = 18// 顯示注解一個number類型

        const count1 = 18// 不顯示注解,ts會自動推導出來類型

        2. string

        const str: string = "前端娛樂圈"// 顯示注解一個string類型

        const str1 = "蛙人"// 不顯示注解,ts會自動推導出來類型

        3. boolean

        const status: string = false; // 顯示注解一個string類型

        const status1 = true; // 不顯示注解,ts會自動推導出來類型

        4. null

        const value: null = null;

        const value: null = undefined// 這一點null類型可以賦值undefined跟在 js中是一樣的,null == undefined

        5. undefined

        const value: undefined = undefined;

        const value: undefined = null// 這一點null類型可以賦值undefined跟在 js中是一樣的,null == undefined

        6. void

        估計到這有一些小伙伴可能對void這個比較陌生,以為只有TypeScript才有的。其實不是哈,在我們JavaScript就已經(jīng)存在void關鍵字啦,它的意思就是無效的,有的小伙伴可能看見過早些項目里面<a href="javascript: void(0)">這是控制a標簽的跳轉(zhuǎn)默認行為。你不管怎么執(zhí)行void方法它都是返回undefined

        那么在我們TypeScriptvoid類型是什么呢。它也是代表無效的,一般只用在「函數(shù)」上,告訴別人這個「函數(shù)」沒有返回值。

        function fn(): void {} // 正確

        function testFn(): void {
            return 1// 報錯,不接受返回值存在
        }

        function fn1(): void return undefined// 顯示返回undefined類型,也是可以的

        function fn2(): void return null// 顯示返回null類型也可以,因為 null == undefined

        7. never

        never「一個永遠不會有值的類型」或者也可以說「一個永遠也執(zhí)行不完的類型」,代表用于不會有值,undefined、null也算做是值。一般這個類型就不會用到,也不用。大家知道這個類型就行。

        const test: never = null// 錯誤
        const test1: never = undefined // 錯誤

        function Person(): never // 正確,因為死循環(huán)了,一直執(zhí)行不完
            while(true) {}
        }

        function Person(): never // 正確,因為遞歸,永遠沒有出口
            Person()
        }

        function Person(): never // 正確 代碼報錯了,執(zhí)行不下去
            throw new Error()
        }

        8. any

        any這個類型代表「任何的」、「任意的」。希望大家在項目中,不要大片定義any類型。雖然它真的好使,那這樣我們寫TypeScript就沒有任何意義了。

        let value: any = ""// 正確
        value = null // 正確
        value = {} // 正確
        value = undefined // 正確

        9. unknown

        unknown類型是我們TypeScript中第二個any類型,也是接受任意的類型的值。它的英文翻譯過來就是「未知的」,我們來看一下栗子

        let value: unknown = ""  
        value = 1;
        value = "fdsfs"
        value = null
        value = {}

        那現(xiàn)在肯定有小伙伴疑惑,誒,那它unknown相當于是any類型,那二者的區(qū)別是什么。我們來看一下

        let valueAny: any = "";
        let valueUnknown: unknown = "";

        valueAny = "蛙人";
        valueUnknown = "前端娛樂圈"

        let status: null = false;
        status = valueAny; // 正確
        status = valueUnknown // 報錯,不能將unknown類型分配給null類型

        我們來看一下上面的,為什么any類型就能被賦值成功,而unknown類型不行呢,從它倆的意義來上看,還是有點區(qū)別的,any任何的,任意的、unknown未知的。所以你給unknown類型賦值任何類型都沒關系,因為它本來就是未知類型嘛。但是你如果把它的unknown類型去被賦值一個null類型,這時人家null這邊不干了,我不接受unknown類型。

        說白了一句話,別人不接受unknown類型,而unknown類型接受別人,哈哈哈哈。

        2. 對象靜態(tài)類型

        說起對象類型,我們肯定都能想到對象包含{}、數(shù)組、、函數(shù)

        1. object && {}

        其實這倆意思一樣,{}、object表示非原始類型,也就是除number,stringboolean,symbolnullundefined之外的類型。

        const list: object = {} // 空對象

        const list1: object = null// null對象

        const list: object = [] // 數(shù)組對象

        const list: {} = {}
        list.name = 1 // 報錯 不可更改里面的字段,但是可以讀取
        list.toString()

        2. 數(shù)組

        const list: [] = []; // 定義一個數(shù)組類型

        const list1: number[] = [1,2// 定義一個數(shù)組,里面值必須是number

        const list2: object[] = [null, {}, []] // 定義一個數(shù)組里面必須是對象類型的

        const list3: Array<number> = [1,2,3// 泛型定義數(shù)組必須是number類型,泛型我們待會講到

        3. 類

        // 類
        class ClassPerson = {
            name"前端娛樂圈"
        }

        const person: ClassPerson = new Person();
        person.xxx = 123// 這行代碼報錯,因為當前類中不存在該xxx屬性

        4. 函數(shù)

        // 函數(shù)
        const fn: () => string = () => "前端娛樂圈" // 定義一個變量必須是函數(shù)類型的,返回值必須是string類型

        3. 函數(shù)類型注解

        這里說一下函數(shù)顯示注解和函數(shù)參數(shù)不會類型推導問題。

        1. 函數(shù)返回類型為number

        function fn(a, b): number {
            return a + b;
        }
        fn(12)

        2. 函數(shù)void

        顯示注解為void類型,函數(shù)沒有返回值。

        function fn(): void {
            console.log(1)
        }

        3. 函數(shù)不會自動類型推導

        可以看到下面的函數(shù)類型,不會自動類型推導,我們實參雖然傳入的1和2,但是形參方面是可以接受任意類型值的,所以系統(tǒng)也識別不出來你傳遞的什么,所以這里得需要我們顯示定義注解類型。

        function testFnQ(a, b{
            return a + b
        }
        testFnQ(1,2)
        微信截圖_20210824233905.png

        我們來改造一下。

        function testFnQ(a:number, b:number) {
            return a + b
        }
        testFnQ(1,2)
        微信截圖_20210825001425.png

        我們再來看一下參數(shù)對象顯示注解類型,也是在:號后面賦值每個字段類型即可。

        function testFnQ(obj : {num: number}{
            return obj.num
        }
        testFnQ({num18})

        4. 元組Tuple

        元組用于表示一個已知數(shù)組的數(shù)量和類型的數(shù)組,定義數(shù)組中每一個值的類型,一般不經(jīng)常使用。

        const arr: [string, number] = ["前端娛樂圈"1]

        const arr: [string, string] = ["前端娛樂圈"1// 報錯

        5. 枚舉Enum

        Enum枚舉類型,可以設置默認值,如果不設置則為索引。

        enum color {
            RED,
            BLUE = "blue",
            GREEN = "green"
        }

        // color["RED"] 0
        // color["BLUE"] blue

        像上面的colorRED沒有設置值,那么它的值則為0,如果BLUE也不設置的話那么它的值則是1,它們這里是遞增。如果設置值則是返回設置的值

        「注意這里還有一個問題,直接來上代碼」

        通過上面學習我們知道了enum可以遞增值,也可以設置默認值。但是有一點得注意一下,enum沒有json對象那樣靈活,enum不能在任意字段上設置默認值。

        比如下面栗子,RED沒有設置值,然后BLUE設置了默認值,但是GREEN又沒有設置,這時這個GREEN會報錯。因為你第二個BLUE設置完默認值,第三又不設置,這時代碼都不知道該咋遞增了,所以報錯。還有一種方案就是你給BLUE可以設置一個數(shù)字值,這時第三個GREEN不設置也會跟著遞增,因為都是number類型。

        // 報錯
        enum color {
            RED,
            BLUE = "blue",
            GREEN
        }

        // good
        enum color {
            RED,    // 0
            BLUE = 4,  // 4
            GREEN      // 5
        }

        比如enum枚舉類型還可以反差,通過valuekey值。像我們json對象就是不支持這種寫法的。

        enum color {
            RED,    // 0
            BLUE = 4,  // 4
            GREEN      // 5
        }

        console.log(color[4]) // BLUE
        console.log(color[0]) // RED

        5. 接口Interface

        接口interface是什么,接口interface就是方便我們定義一處代碼,多處復用。接口里面也存在一些修飾符。下面我們來認識一下它們吧。

        1. 接口怎么復用

        比如在講到這之前,我們不知道接口這東西,可能需要給對象定義一個類型的話,你可能會這樣做。

        const testObj: { name: string, age: number } = { name"前端娛樂圈"age18 }

        const testObj1: { name: string, age: number } = { name"蛙人"age18 }

        我們用接口來改造一下。

        interface Types {
            name: string, 
            age: number
        }

        const testObj: Types = { name"前端娛樂圈"age18 }

        const testObj1: Types = { name"蛙人"age18 }

        可以看到使用interface關鍵字定義一個接口,然后賦值給這兩個變量,實現(xiàn)復用。

        2. readonly修飾符

        readonly類型,只可讀狀態(tài),不可更改。

        interface Types {
            readonly name: string, 
            readonly age: number
        }

        const testObj: Types = { name"前端娛樂圈"age18 }

        const testObj1: Types = { name"蛙人"age18 }

        testObj.name = "張三" // 無法更改name屬性,因為它是只讀屬性
        testObj1.name = "李四" // 無法更改name屬性,因為它是只讀屬性

        3. ?可選修飾符

        可選修飾符以?定義,為什么需要可選修飾符呢,因為如果我們不寫可選修飾符,那interface里面的屬性都是必填的。

        interface Types {
            readonly name: string, 
            readonly age: number,
            sex?: string
        }

        const testObj: Types = { name"前端娛樂圈"age18}

        4. extends繼承

        我們的interface也是可以繼承的,跟「ES6」Class類一樣,使用extends關鍵字。

        interface Types {
            readonly name: string, 
            readonly age: number,
            sex?: string
        }

        interface ChildrenType extends Types { // 這ChildrenType接口就已經(jīng)繼承了父級Types接口
            hobby: []
        }
            
        const testObj: ChildrenType = { name"前端娛樂圈"age18, hobby: ["code""羽毛球"] }

        5. propName擴展

        interface里面這個功能就很強大,它可以寫入不在interface里面的屬性。

        interface Types {
            readonly name: string, 
            readonly age: number,
            sex?: string,
        }

        const testObj: Types = { name"前端娛樂圈"age19hobby: [] } 

        上面這個testObj這行代碼會爆紅,因為hobby屬性不存在interface接口中,那么我們不存在的接口中的,還不讓人家寫了?。這時候可以使用「自定義」就是上面的propName。

        interface Types {
            readonly name: string, 
            readonly age: number,
            sex?: string,
            [propName: string]: any // propName字段必須是 string類型 or number類型。 值是any類型,也就是任意的
        }

        const testObj: Types = { name"前端娛樂圈"age19hobby: [] } 

        在運行上面代碼,就可以看到不爆紅了~

        6. Type

        我們再來看一下Type,這個是聲明類型別名使的,別名類型只能定義是:基礎靜態(tài)類型對象靜態(tài)類型、元組、聯(lián)合類型。

        ?

        注意:type別名不可以定義interface

        ?
        type Types = string;

        type TypeUnite = string | number

        const name: typeUnite = "前端娛樂圈"
        const age: typeUnite = 18

        1. 那么type類型別名和interface接口有什么區(qū)別呢

        1. type不支持interface聲明
        type Types = number
        type Types = string // 報錯, 類型別名type不允許出現(xiàn)重復名字

        interface Types1 {
            name: string
        }

        interface Types1 {
            age: number
        }

        // interface接口可以出現(xiàn)重復類型名稱,如果重復出現(xiàn)則是,合并起來也就是變成 { name:string, age: number }

        第一個Types類型別名type不允許出現(xiàn)重復名字,interface接口可以出現(xiàn)重復類型名稱,如果重復出現(xiàn)則是,合并起來也就是變 { name:string, age: number }

        「再來看一下interface另一種情況」

        interface Types1 {
            name: string
        }

        interface Types1 {
            name: number
        }

        可以看到上面兩個同名稱的interface接口,里面的屬性也是同名稱,但是類型不一樣。這第二個的Types1就會爆紅,提示:「后續(xù)聲明的接口,必須跟前面聲明的同名屬性類型必須保持一致」,把后續(xù)聲明的name它類型換成string即可。

        2. type支持表達式 interface不支持
        const count: number = 123
        type testType = typeof count

        const count: number = 123

        interface testType {
            [name: typeof count]: any // 報錯
        }

        可以看到上面type支持表達式,而interface不支持

        3. type 支持類型映射,interface不支持
        type keys = "name" | "age"  
        type KeysObj = {
            [propName in keys]: string
        }

        const PersonObj: KeysObj = { // 正常運行
            name"蛙人",
            age"18"


        interface testType {
            [propName in keys]: string // 報錯
        }

        7. 聯(lián)合類型

        聯(lián)合類型|表示,說白了就是滿足其中的一個類型就可以。

        const statusTest: string | number = "前端娛樂圈"

        const flag: boolean | number = true

        再來看一下栗子。我們用函數(shù)參數(shù)使用「聯(lián)合類型」看看會發(fā)生什么

        function testStatusFn(params: number | string{
            console.log(params.toFixed()) // 報錯
        }

        testStatusFn(1)

        上面我們說過了,函數(shù)參數(shù)類型不能類型自動推導,更何況現(xiàn)在用上「聯(lián)合類型」,系統(tǒng)更懵逼了,不能識別當前實參的類型。所以訪問當前類型上的方法報錯。

        接下來帶大家看一些類型保護,聽著挺高級,其實這些大家都見過。別忘了記得關注:「前端娛樂圈」 公眾號哦,嘻嘻

        1. typeof

        function testStatusFn(params: number | string{
            console.log(params.toFixed()) // 報錯
        }
        testStatusFn(1)

        「改造后」

        // 正常
        function testStatusFn(params: string | number{
            if (typeof params == "string") {
                console.log(params.split)
            }

            if (typeof params == "number") {
                console.log(params.toFixed)
            }
        }

        testStatusFn(1)

        2. in

        // 報錯
        interface frontEnd {
            name: string
        }

        interface backEnd {
            age: string
        }

        function testStatusFn(params: frontEnd | backEnd{
            console.log(params.name)
        }

        testStatusFn({name"蛙人"})

        「改造后」

        // 正常
        function testStatusFn(params: frontEnd | backEnd{
            if ("name" in params) {
                console.log(params.name)
            }

            if ("age" in params) {
                console.log(params.age)
            }
        }

        testStatusFn({name"蛙人"})

        3. as 斷言

        // 報錯
        interface frontEnd {
            name: string
        }

        interface backEnd {
            age: string
        }

        function testStatusFn(params: frontEnd | backEnd{
            console.log(params.name)
        }

        testStatusFn({name"蛙人"})

        「改造后」

        // 正常
        function testStatusFn(params: frontEnd | backEnd{
            if ("name" in params) {
                const res = (params as frontEnd).name
                console.log(res)
            }
            
            
            if ("age" in params) {
                const res = (params as backEnd).age
                console.log(res)
            }
        }

        testStatusFn({age118})

        8. 交叉類型

        交叉類型就是跟聯(lián)合類型相反,它用&表示,交叉類型就是兩個類型必須存在。這里還用上面的「聯(lián)合類型」的栗子來看下。

        interface frontEnd {
            name: string
        }

        interface backEnd {
            age: number
        }

        function testStatusFn(params: frontEnd & backEnd) {}

        testStatusFn({age: 118, name: "前端娛樂圈"})

        這里我們可以看到實參必須傳入兩個**接口(interface)**全部的屬性值才可以。「聯(lián)合類型」是傳入其中類型就可以。

        「注意:我們的接口interface出現(xiàn)同名屬性」

        interface frontEnd {
            name: string
        }

        interface backEnd {
            name: number
        }

        function testStatusFn(params: frontEnd & backEnd) {
            console.log(params)
        }

        testStatusFn({name: "前端"})

        上面我們兩個接口類型中都出現(xiàn)了同名屬性,但是類型不一樣,這時類型就會變?yōu)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">never。

        微信截圖_20210825181810.png

        9. 泛型

        泛型是TypeScript中最難理解的了,這里我盡量用通俗易懂的方式講明白。

        function test(a: string | number, b: string | number{
            console.log(a, b)
        }
        test(1"前端娛樂圈")

        比如上面栗子,函數(shù)參數(shù)注解類型定義stringnumber,調(diào)用函數(shù)實參傳入也沒什么問題,但是有個需求,就是實參我們「必須傳入同樣的類型」(傳入兩個number類型)。雖然上面這種「聯(lián)合類型」也可以實現(xiàn),但是如果我們要在加一個boolean類型,那么「聯(lián)合類型」還得在追加一個boolean,那這樣代碼太冗余了。

        這時就需要用到「泛型」了,「泛型」是專門針對不確定的類型使用,并且靈活。泛型的使用大部分都是使用<T>,當然也可以隨便使用,如:<Test>、<Custom>都可以。

        function test<T>(a: T, b: T{
            console.log(a, b)
        }
        test<number>(1"前端娛樂圈"// 調(diào)用后面跟著尖括號這就是泛型的類型,這時報錯,因為在調(diào)用的使用類型是number,所以只能傳入相同類型的

        test<boolean>(truefalse

        test<string>("前端娛樂圈""蛙人")

        上面這使用「泛型」就解決了我們剛才說的傳入同一個類型參數(shù)問題,但是「泛型」也可以使用不同的參數(shù),可以把調(diào)用類型定義為<any>

        function test<T>(a: T, b: T{
            console.log(a, b)
        }

        test<any>(1"前端娛樂圈")

        但是上面這種又有一種問題,它可以傳入對象,但是如果我們只希望傳入number類型和string類型。那么我們「泛型」也給我們提供了**約束「類型。「泛型」使用extends進行了」類型約束**,只能選擇stringnumber類型。

        function test<T extends number | stringY extends number | string>(a: T, b: Y{
            console.log(a, b)
        }

        test<number, string>(18"前端娛樂圈")

        test<string, number>("前端娛樂圈"18)

        這時,傳入泛型時使用,逗號分隔,來定義每一個類型希望是什么。記住,只有我們不確定的類型,可以使用泛型。

        10. 模塊

        TypeScript也支持importexport這里大多數(shù)小伙伴都知道,這里都不多講啦。

        // 導入

        import xxx, { xxx } from "./xxx"

        // 導出

        export default {}

        export const name = "前端娛樂圈"

        如有不明白的小伙伴,可以看我以前文章 聊聊什么是CommonJs和Es Module及它們的區(qū)別

        11. Class類

        ?

        以下這三個修飾符是在TypeScript類中才能使用,在JavaScript類中是不支持的。

        ?
        報錯.png

        1. public

        public的公共屬性,就是不管在的內(nèi)部還是外部,都可以訪問該「屬性」「方法」。默認定義的「屬性」「方法」都是public。

        class Person {
         name = "前端娛樂圈";
         public age = 18;
        }
        const res = new Person();
        console.log(res.name, res.age) // 前端娛樂圈 18

        上面可以看到打印結(jié)果都能顯示出來,name屬性沒有定義public公共屬性,所以里面定義的「屬性」「方法」默認都是public定義。

        2. private

        private的私有屬性,只有在當前里面才能訪問,當前就是{}里面區(qū)域內(nèi)。在{}外面是不能訪問private定義的「屬性」「方法」

        class Person {
         private name = "前端娛樂圈";
         private age = 18;
        }
        const res = new Person();
        console.log(res.name, res.age) // 這倆行會爆紅,當前屬性為私有屬性,只能在類內(nèi)部訪問

        class Scholl extends Person {
            getData() {
                return this.username + "," + this.age
            }
        }
        const temp = new Scholl()
        console.log(temp.getData()) // 爆紅~,雖然繼承了Person類,但是private定義是只能在當前類訪問,子類也不能訪問。

        3. protected

        protected的保護屬性,只有在「當前類」「子類」可以訪問。也就是說用protected屬性定義的「子類」也可以訪問。

        class Person {
         protected username = "前端娛樂圈";
         protected age = 18;
        }
        const res = new Person();
        console.log(res.name, res.age) // 這倆行會爆紅,當前屬性為私有屬性,只能在類內(nèi)部訪問

        class Scholl extends Person {
            getData() {
                return this.username + "," + this.age
            }
        }
        const temp = new Scholl()
        console.log(temp.getData()) // 前端娛樂圈,18??梢哉TL問父類的屬性

        4. implements

        implements關鍵字只能在class中使用,顧名思義,實現(xiàn)一個新的類,從父級或者從接口實現(xiàn)所有的屬性和方法,如果在PersonAll類里面不寫進去接口里面已有的屬性和方法則會報錯。

        interface frontEnd {
            name: string,
            fn() => void
        }

        class PersonAll implements frontEnd {
            name"前端娛樂圈";
            
            fn() {
                
            }
        }

        5. 抽象類

        抽象類使用abstract關鍵字定義。abstract抽象方法不能實例化,如果,抽象類里面方法是抽象的,那么本身的類也必須是抽象的,抽象方法不能寫函數(shù)體。父類里面有抽象方法,那么子類也必須要重新該方法。

        // 抽象類
        abstract class Boss {
            name = "秦";
            call() {} // 抽象方法不能寫函數(shù)體
        }

        class A extends Boss {
            call() {
                console.log(this.name);
                console.log("A")
            }
        }

        class B extends Boss {
            call() {
                 console.log("B")
            }
        }

        new A().call()

        該抽象類使用場景,比如A需求或者B需求正好需要一個公共屬性,然后本身還有一些自己的邏輯,就可以使用抽象類,抽象類只能在TypeScript中使用。

        12. 命名空間namespace

        我們學到現(xiàn)在可以看到,不知道小伙伴們發(fā)現(xiàn)沒有,項目中文件是不是不能有重復的變量(不管你是不是一樣的文件還是其它文件),否則就直接爆紅了。命名空間一個最明確的目的就是解決重名問題。

        命名空間使用namespace關鍵字來定義,來看栗子吧。

        「index.ts」

        namespace SomeNameSpaceName { 
            const q = {}

            export interface obj {
                name: string
            }
        }

        上面這樣,就定義好了一個命名空間,可以看到變量q沒有寫export關鍵字,這證明它是內(nèi)部的變量,就算別的.ts文件引用它,它也不會暴露出去。而interface這個obj接口是可以被全局訪問的。

        「我們在別的頁面訪問當前命名空間」

        1. reference引入

        /// <reference path="./index.ts" />
        namespace SomeNameSpaceName { 
         export class person implements obj {
          name: "前端娛樂圈"
         }
        }

        2. import

        export interface valueData {
             name: string
        }
        import { valueData } from "./xxx.ts"

        這時使用命名空間之后完全可以解決不同文件重名爆紅問題。

        13. tsConfig.json

        這個tsconfig文件,是我們編譯ts文件,如何將ts文件編譯成我們的js文件。tsc -init這個命令會生成該文件出來哈。執(zhí)行完該命令,我們可以看到根目錄下會生成一個tsconfig.json文件,里面有一堆屬性。

        那么我們怎么將ts文件編譯成js文件呢,直接執(zhí)行tsc命令可以將根目錄下所有的.ts文件全部編譯成.js文件輸出到項目下。

        更多配置文檔,請參考官網(wǎng)

        {
            // include: ["*.ts"] // 執(zhí)行目錄下所有的ts文件轉(zhuǎn)換成js文件
            // include: ["index.ts"] // 只將項目下index.ts文件轉(zhuǎn)換為js文件
            // files: ["index.ts"] // 跟include一樣,只執(zhí)行當前數(shù)組值里面的文件,當前files必須寫相對路徑
            // exclude: ["index.ts"] // exclude就是除了index.ts不執(zhí)行,其它都執(zhí)行
            
            compilerOptions: {
                removeCommentstrue// 去掉編譯完js文件的注釋
                outDir"./build"// 最終輸出的js文件目錄
                rootDir"./src"// ts入口文件查找
            }
        }

        八、實用類型

        最后來說一下實用類型,TypeScript標準庫自帶了一些實用類型。這些實用類都是方便接口Interface使用。這里只列舉幾個常用的,更多實用類型官網(wǎng)

        1. Exclude

        從一個類型中排除另一個類型,只能是「聯(lián)合類型」,從TypesTest類型中排除UtilityLast類型。

        「適用于:并集類型」

        interface UtilityFirst {
            name: string
        }

        interface UtilityLast {
            age: number
        }

        type TypesTest = UtilityFirst | UtilityLast;

        const ObjJson: Exclude<TypesTest, UtilityLast> = {
            name: "前端娛樂圈"
        }

        2. Extract

        Extract正好跟上面那個相反,這是選擇某一個可賦值的「聯(lián)合類型」,從TypesTest類型中只選擇UtilityLast類型。

        「適用于:并集類型」

        interface UtilityFirst {
            name: string
        }

        interface UtilityLast {
            age: number
        }

        type TypesTest = UtilityFirst | UtilityLast;

        const ObjJson: Extract<TypesTest, UtilityLast> = {
            age1
        }

        3. Readonly

        把數(shù)組或?qū)ο蟮乃袑傩灾缔D(zhuǎn)換為只讀的。這里只演示一下對象栗子,數(shù)組同樣的寫法。

        「適用于:對象、數(shù)組」

        interface UtilityFirst {
            name: string
        }

        const ObjJson: Readonly<UtilityFirst> = {
            name"前端娛樂圈"
        }
        ObjJson.name = "蛙人" // 報錯 只讀狀態(tài)

        4. Partial

        把對象的所有屬性設置為選的。我們知道interface只要不設置?修飾符,那么對象都是必選的。這個實用類可以將屬性全部轉(zhuǎn)換為可選的。

        「適用于:對象」

        interface UtilityFirst {
            name: string
        }

        const ObjJson: Partial<UtilityFirst> = {
            
        }

        5. Pick

        Pick選擇對象類型中的部分key值,提取出來。第一個參數(shù)目標值,第二個參數(shù)「聯(lián)合」key

        「適用于:對象」

        interface UtilityFirst {
            name: string,
            age: number,
            hobby: []
        }

        const ObjJson: Pick<UtilityFirst, "name" | "age"> = {
            name"前端娛樂圈",
            age18
        }

        6. Omit

        Omit選擇對象類型中的部分key值,過濾掉。第一個參數(shù)目標值,第二個參數(shù)「聯(lián)合」key

        「適用于:對象」

        interface UtilityFirst {
            name: string,
            age: number,
            hobby: string[]
        }

        const ObjJson: Omit<UtilityFirst, "name" | "age"> = {
            hobby: ["code""羽毛球"]
        }

        7. Required

        Required把對象所有可選屬性轉(zhuǎn)換成必選屬性。

        「適用于:對象」

        interface UtilityFirst {
            name?: string,
            age?: number,
            hobby?: string[]
        }

        const ObjJson: Required<UtilityFirst> = {
            name: "蛙人",
            age: 18,
            hobby: ["code"]
        }

        8. Record

        創(chuàng)建一個對象結(jié)果集,第一個參數(shù)則是key值,第二個參數(shù)則是value值。規(guī)定我們只能創(chuàng)建這里面字段值。

        「適用于:對象」

        type IndexList = 0 | 1 | 2

        const ObjJson: Record<IndexList, "前端娛樂圈"> = {
            0"前端娛樂圈",
            1"前端娛樂圈",
            2"前端娛樂圈"


         參考資料

        [1]

        聊聊什么是CommonJs和Es Module及它們的區(qū)別: https://juejin.cn/post/6938581764432461854

        [2]

        官網(wǎng): https://www.tslang.cn/docs/handbook/compiler-options.html

        [3]

        官網(wǎng): https://www.typescriptlang.org/docs/handbook/utility-types.html

        [4]

        了不起的 TypeScript 入門教程: https://juejin.cn/post/6844904182843965453

        [5]

        TypeScript中文網(wǎng): https://www.tslang.cn/docs/handbook/basic-types.html


        請你喝杯?? 記得三連哦~

        1.閱讀完記得給?? 醬點個贊哦,有?? 有動力

        2.關注公眾號前端那些趣事,陪你聊聊前端的趣事

        3.文章收錄在Github frontendThings 感謝Star?

        瀏覽 39
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            大雞巴乱人妻1~14 | 女人脱了内裤张开双腿让男人桶 | 啊灬啊灬快灬高潮了 | 香港三级韩国三级日本三级 | 中文字幕在线观看 | 一级操 | 国产尤物视频在线观看 | 黄片成人免费 | 国产操逼在线视频 | 天天插AV|