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類型標(biāo)注相關(guān)概念一覽

        共 10283字,需瀏覽 21分鐘

         ·

        2020-08-28 04:38

        來源:SegmentFault 思否社區(qū)

        作者:LnEoi




        背景


        用TypeScript重構(gòu)了一遍業(yè)務(wù)后臺,TS很大一部分在處理類型標(biāo)注,基礎(chǔ)的類型很容易上手,但到泛型一塊,抽象程度一下子就高了起來,提供的許多工具也復(fù)雜了起來。重構(gòu)的時候一直想整理一份方便查詢的筆記一直沒空,現(xiàn)在總算抽出時間整理了一份,將于類型有關(guān)的部分整理了出來,其他部分還需要自行翻閱相關(guān)文檔。


        筆記類似大綱,知道什么情況下有什么可以用,有一個范圍概念,具體細(xì)節(jié)通過筆記提供的關(guān)鍵字再搜索相關(guān)文檔仔細(xì)了解。





        基礎(chǔ)類型


        TS是JS的超集,所以JS基礎(chǔ)的類型都包含在內(nèi):
        boolean、number、string、symbol、array([])、object({})、null、undefined


        • TS還提供了其他更加詳細(xì)的類型標(biāo)識:

        • any:任意類型,TS將不對其進(jìn)行類型檢測

        • unknown:未知類型,在早期對于未知類型我們一般標(biāo)注any,但標(biāo)注any將不會對類型進(jìn)行檢測,unknown則在對變量第一次賦值后,除了any類型,其他類型禁止再賦值給此變量,同時在使用其類型所對應(yīng)的方法時也需要先收縮類型,才能正常的使用

        • void:無返回,當(dāng)一個函數(shù)沒有返回值的時候此類型標(biāo)識

        • never:當(dāng)函數(shù)永遠(yuǎn)沒有返回值的時候用此類型標(biāo)識。如始終拋出異常的函數(shù),其返回值就是never

        • tuple:元組,數(shù)組的更精確的標(biāo)識方法,可以限定數(shù)組的數(shù)量與每個位的類型

        • enum:枚舉,可以給每一個預(yù)定值的數(shù)值或是字符串提供簡明的名稱,方便編寫時區(qū)分

        • ... | ...:類型字面量,如'Red' | 'Green' | 'Blue',此時這變量就只能賦值這三種字符串,如果賦值其他字符串時將會報錯,也可以是數(shù)字字面量 1 | 2 | 3


        其他

        • 默認(rèn)情況下null和undefined是所有類型的子類型,可以將這兩個值賦值給任意類型。
        • never類型也是任何類型的子類型。但其他類型無法賦值給never類型,只有never才能賦值給never類型。
        • object與Object,這兩個注釋類型只有一個大小寫之分,用Object申明的類型可以訪問Object對象的默認(rèn)方法,但object則不行。





        基本概念


        : (冒號標(biāo)注)


        TS有自動類型推斷,當(dāng)賦上初始值后TS會生成相應(yīng)的類型標(biāo)注,所以一般情況下不必手動添加


        let variate: boolean = truelet variate: number = 1let variate: string = 'one'let variate: number[] = [1,3,4,6] // 數(shù)組let variate: { first: string, second: number } = { first: 'one', second: 2 } // 對象let sym1 = Symbol('key') // symbollet variate: number[string, number] = ['one', 2] // 元組enum color {Red, Green, Blue} // 枚舉


        函數(shù)參數(shù)的類型標(biāo)注


        function func(params: {  first: string;  second: number;}): void {}const func = function(params: {  first: string;  second: number;}): void {}


        函數(shù)的類型標(biāo)注


        const func: (first: string, second: number) => void = function(params) {}const func: (first: string, second: number) => void = () => {}  // 這種寫法很不容易分辨,只要記錄函數(shù)的類型標(biāo)注是必須顯示指定返回值的,所以當(dāng)看到返回值的標(biāo)注才是類型標(biāo)注完全結(jié)束





        interface (接口)


        此是最常用的類型標(biāo)注方式。
        如上例變量標(biāo)注也可以用接口替代:


        interface IVariate {  first: string;  second: number;}let variate: IVariate = { first: 'one', second: 2 }


        其他特性


        ??可選標(biāo)識符

        interface IVariate {  first: string;  second?: number;}


        readonly?只讀標(biāo)識符


        interface IVariate {  first: string;  readonly second: number;}


        [key: string | number]: any?任意數(shù)量標(biāo)識


        有時候類型數(shù)量是動態(tài)的,但類型是指定需要約束的,可以這樣寫

        interface IVariate {  first: string;  readonly second: number;  [key: string]: number;}

        extends?接口的繼承


        interface IVariate {  first: string;  second: number;}interface IVariate2 extends IVariate {  third: string}等價于:interface IVariate2 {  first: string;  second: number;  third: string;}


        利用,可以進(jìn)行多繼承


        interface IVariate3 extends IVariate, IVariate2 {  fourth: string}


        類型合并


        interface IVariate {  first: string;  second: number;}interface IVariate {  third: number;}


        重復(fù)申明類型默認(rèn)會將申明合并起來,如果有重復(fù)定義的類型標(biāo)注,后面的會把前面的覆蓋。


        函數(shù)


        函數(shù)參數(shù)的類型標(biāo)注


        interface IParams {  first: string;  second: number;}function func(params: IParams) {}const func = function(params: IParams) {}


        函數(shù)的類型標(biāo)注


        完整的標(biāo)注函數(shù)參數(shù)以及函數(shù)返回值,與參數(shù)類型標(biāo)注一樣,只是將定義移動到interface中。


        interface IFunc {  (first: string, second: number): void  // 這里需要注意,在interface中函數(shù)的類型標(biāo)注是冒號(:)而不是箭頭(=>)}const func: IFunc = function(params) {}const func: IFunc = () => {}

        不定參數(shù)的類型標(biāo)注

        const func = function(...params: any[]) {}
        可選參數(shù)的類型標(biāo)注

        需要注意,可選類型之后不能有必選類型。

        const func = function(first: string, second?: number) {}
        不定參數(shù)的類型標(biāo)注
        const func = function(...params: any[]) {}
        this類型標(biāo)注

        由于JS的this是動態(tài)指向的,所以this類型默認(rèn)標(biāo)注為any,如果需要顯式標(biāo)注可以在函數(shù)第一個參數(shù)位進(jìn)行標(biāo)注

        const func = function(this: void, first: string, second?: number) {}
        函數(shù)重載

        當(dāng)傳入不同參數(shù)需要返回不同類型時,此時可以用函數(shù)重載來標(biāo)識

        function func(data: number): numberfunction func(data: string): stringfunction func(data: number | string): string | number { // 必須要有一個函數(shù)支持所有類型    if(typeof data === 'number') return data+1    return data}



        這一塊跟C#很像,基礎(chǔ)的元素都搬過來了,可以直接使用。


        類的申明


        class People {    name: string;    constructor(name: string) {        this.name = name;    }    hello() {        return `Hello ${this.name}`;    }}

        類的繼承

        class Student extends People {    number: number = 0    constructor(name: string, number: number) {        super(name);        this.number = number    }    hello() {        return `Hello ${this.name}, Number ${this.number}`;    }}

        修飾符

        修飾符與其他語言一樣,public、private、protected。不標(biāo)明時默認(rèn)為public。
        靜態(tài)屬性static,只讀readonly,可選?。

        存取器get、set

        class People2 {    private _name: string;    constructor(name: string) {        this.name = name;    }    get name(): string {        return this._name    }    set name(newName: string) {        this._name = `name: ${newName}`    }}

        abstract抽象類 抽象方法


        標(biāo)識abstract關(guān)鍵詞,類與方法都不必在定義時被實(shí)現(xiàn),必須在繼承的類中實(shí)現(xiàn)具體方法

        abstract class People3 {    abstract hello() {}}

        implements類的接口繼承

        類的繼承只能是單繼承,沒辦法多繼承,但實(shí)際開發(fā)中常常會有一個功能需要多個類使用,這時候可以用接口


        interface IStudy {    gender: string}interface IGrade {    grade(): string}class Student2 extends People implements IStudy, IGrade // implements 可以用逗號分隔指定多個{    number: number = 0    gender: string    constructor(name: string, number: number, gender: string) {        super(name);        this.number = number        this.gender = gender    }    hello() {        return `Hello ${this.name}, Number ${this.number}`;    }    grade(){        return 'A'    }}


        |?聯(lián)合類型


        通常情況下一個變量一個類型是不夠用的,所以會需要指定多種類型,這時候就需要用到聯(lián)合類型符號


        let variate: number | string // 這樣就能支持number類型與string類型


        &?交叉類型


        有時候新的類型是兩個舊類型的并集,這時候可以用交叉類型運(yùn)算符生成新的類型,而不必重新申明


        let variate: IVariate & { data: string } // 會生成新的類型,其中包含 first second data 三個key

        as、<>類型斷言


        <>斷言寫在前面variate,但因?yàn)榕cJSX語法會有沖突,所以一般使用as語法,as語法寫在后面variate as string。


        有的場景我們要使用一個類型的內(nèi)部值,但TS又會報錯時,這時候可以直接強(qiáng)制將類型收縮。


        某些條件下外部傳入的值始終符合預(yù)期無需判斷,這時候我們也可以使用斷言。


        interface IA {  first: string;  second: number;}interface IB {  name: string;  age: number;}function func(data: IA | IB) {    if((data as IB).name) // ...省略    else return // ...省略}
        function func2(data: IA) { (data as any as IB).name // 當(dāng)原本沒有標(biāo)注類型IB時,無法直接斷言,可以使用兩次斷言強(qiáng)制指定一個類型}


        is關(guān)鍵字


        is可以將類型收縮成某一類型


        function isNumber(x: any): x is number {  return typeof x === 'number'}


        !關(guān)鍵字


        某些場景類型定義變量是包含undefined的,但我們使用的時候確定這時候無需判斷,可以使用!斷言來消除警告提示。


        interface IVariate {  first: string;  second: number;}let variate: IVariate | undefinedlet second = variate!.second


        type?類型別名


        類型別名與interface一樣,但比interface更加強(qiáng)大通用。
        比如類型字面量想要重新起一個名稱方便使用


        type color = 'Red' | 'Green' | 'Blue'


        甚至可以直接給原始類型起別名


        type name = string


        或是給interface再起別名


        type funcParams = IParams


        也可以使用&、|


        type funcParams2 = IParams & IParams2type funcParams2 = IParams | IParams2





        泛型


        此前的基礎(chǔ)概念大多數(shù)熟悉面向?qū)ο缶幊陶Z言的可以很快就上手,但到泛型一塊,概念性的東西是多了起來,語法也越漸變得復(fù)雜起來,TS制定了一套語法,除了寫業(yè)務(wù)邏輯,我們還需要對JS類型進(jìn)行編程。


        為什么會有泛型呢?在一般使用中,類型相對固定,是可預(yù)期的。但如果要寫通用組件時,我們沒辦法完全預(yù)期傳入的類型和返回類型,有一些返回類型可能是需要用戶自定義的,這時候就需要用到泛型來讓用戶在外部標(biāo)注類型。


        泛型符號


        跟斷言很像,但括號這里是在使用時傳入的定義類型,命名為T,其中符號可以隨意自定義,但有一些常用的關(guān)鍵字:T為type,U為T的下一位,K為key,V為Value,N為Number,E為Element


        使用時類似這樣:


        function func(arg1: T, arg2: U): [T, U] {    return [arg1, arg2]}const func = (arg1: T, arg2: U) => [arg1, arg2]
        class People { name: string; data: T}
        // 接口中使用泛型interface IArg { arg1: T; arg2: U;}


        基礎(chǔ)泛型工具


        keyof獲取鍵名工具


        要處理的類型往往是一個集合,所以需要有一個工具可以獲取集合中的鍵名、鍵值


        interface IParams {  first: string;  second: number;}
        // 獲取鍵名type keyList = keyof IParams; // "first" | "second"// 獲取鍵值type keyList = IParams[keyof IParams]; // string | number

        in映射工具

        in可以將keyof每一次循環(huán)出的值映射給新的變量。
        比如我們遇到了一個新場景,同樣是使用IParams類型,但其中所有參數(shù)是可選的,并非默認(rèn)必選的,這時候我們新建一個重復(fù)的類型就很麻煩,可以使用in keyof來將舊類型轉(zhuǎn)換為新類型


        // 可以使用type構(gòu)建我們處理工具Partialtype Partial = {  [P in keyof T]?: T[P]}// 當(dāng)做泛型,將定義的類型傳入type IParamsPartial = Partial // 是不是有類型編程的味道了
        // 去除可選可用-號標(biāo)識type Required = { [P in keyof T]-?: T[P]}type IParamsRequired = Required

        extends繼承

        同樣的邏輯,可以用來約束泛型的格式。用U extends TU繼承自T,具有T中的定義,所以泛型傳入的參數(shù)必須實(shí)現(xiàn)T中的定義

        // 我們約束傳入的值必須帶name屬性 并且值類型為stinginterface IArg {  name: string}function func(arg: T){  return arg}
        // 使用func<{age: number}>({age: 1}) // 當(dāng)傳入泛型的類型不符合約束時會提示錯誤 Type '{ age: number; }' does not satisfy the constraint 'IArg'. Property 'name' is missing in type '{ age: number; }' but required in type 'IArg'
        func<{name: string, age: number}>({name: 'name', age: 1}) // 只有泛型類型加上指定的name: string時才會正常


        可以與keyof組合使用。


        比如我們創(chuàng)建一個函數(shù),第一個參數(shù)傳入一個對象,第二個參數(shù)傳入對象的鍵名,返回此鍵名對應(yīng)的值。此時鍵名參數(shù)就是動態(tài)的了,寫any無法達(dá)到類型檢測的目的,可以使用extends keyof來進(jìn)行約束



        function getObjectValue(Object: T, key: K) {  return Object[key];}
        const lsit = { a: 1, b: 2, c: 3 }getObjectValue(lsit, 'a'); // 通過 返回1getObjectValue(lsit, 'e'); // 報錯 Argument of type '"e"' is not assignable to parameter of type '"a" | "b" | "c"'.

        infer待推斷變量工具


        infer必須與extends結(jié)合使用,語句格式T extends (infer U)?true : false,(infer U)部分就是我們填寫將要匹配的類型推斷主體,類型T滿足類型U,執(zhí)行true中的邏輯,否則執(zhí)行false中的邏輯。


        手冊的例子就很好的展示了多種類型的推斷匹配:


        type Unpacked =    T extends (infer U)[] ? U : // 如果傳入的是數(shù)組 則將數(shù)組的類型命名為U 并且返回U類型    T extends (...args: any[]) => infer U ? U :  // 如果傳入的是函數(shù) 則將函數(shù)的返回值命名為U 并且返回U類型    T extends Promise ? U :  // 如果傳入的是Promise 則將Promise的泛型參數(shù)命名為U 并且返回U類型    T;  // 如果所有皆否 則返回T類型
        type T0 = Unpacked; // stringtype T1 = Unpacked; // stringtype T2 = Unpacked<() => string>; // stringtype T3 = Unpacked>; // stringtype T4 = Unpacked[]>; // Promisetype T5 = Unpacked[]>>; // string


        內(nèi)置泛型工具


        TS提供了一些常用的類型工具。

        Partial?(TypeScript 2.1)

        將傳入的類型的所有屬性設(shè)置為可選。

        type Partial = {  [P in keyof T]?: T[P]}

        Required?(TypeScript 2.8)

        將傳入的類型的所有屬性設(shè)置為必選。

        type Required = {  [P in keyof T]-?: T[P]}

        Readonly?(TypeScript 2.1)

        將傳入的類型的所有屬性設(shè)置為只讀。


        type Readonly = {  readonly [P in keyof T]: T[P]}Record (TypeScript 2.1)

        將傳入的K類型,重新定義為T類型。


        type Record = {  [P in K]: T;}Exclude (TypeScript 2.8)

        從T類型中排除所有可以賦值給U的類型,生成新類型

        type Exclude = T extends U ? never : T;
        Extract?(TypeScript 2.8)

        從T類型中提取所有可以賦值給U的類型,生成新類型。


        type Extract = T extends U ? T : never;
        Pick?(TypeScript 2.1)

        從T類型中提取K鍵名的元素,生成新類型。

        type Pick = {  [P in K]: T[P];}

        Omit?(TypeScript 3.5)

        從T類型中排除K鍵名的元素,生成新類型。

        type Omit = Pick<  T,  Exclude>

        NonNullable?(TypeScript 2.8)

        從T類型中排除ull或者undefined類型,生成新類型。


        type NonNullable = T extends null | undefined ? never : T;ReturnType (TypeScript 2.8)

        獲取一個函數(shù)類型定義的返回類型。


        type ReturnType any> = T extends (...args: any[]) => infer R ? R : any;
        Parameters

        獲取一個函數(shù)的參數(shù)類型。

        type Parameters any> = T extends (...args: infer P) => any ? P : never;
        ConstructorParameters

        獲取一個構(gòu)造函數(shù)的參數(shù)類型,以數(shù)組格式返回。


        type ConstructorParameters any> = T extends new (...args: infer P) => any ? P : never;
        InstanceType?(TypeScript 2.8)


        獲取一個類的實(shí)例類型。


        type InstanceType any> = T extends new (...args: any[]) => infer R ? R : any;


        相關(guān)資料


        TypeScript文檔:https://www.tslang.cn/docs/home.html

        TyepScript Handbook:

        https://www.typescriptlang.org/docs/handbook/intro.html
        TypeScript Handbook 中文版:

        https://zhongsp.gitbooks.io/typescript-handbook/content/

        TypeScript Deep Dive:https://basarat.gitbook.io/typescript/
        TypeScript Deep Dive 中文版:https://jkchao.github.io/typescript-book-chinese/
        TypeScript入門教程:https://ts.xcatliu.com/
        TypeScript Web版:https://www.typescriptlang.org/zh/play
        TypeScript 內(nèi)置工具泛型:

        https://github.com/chenxiaochun/blog/issues/67





        點(diǎn)擊左下角閱讀原文,到?SegmentFault 思否社區(qū)?和文章作者展開更多互動和交流。

        -?END -


        瀏覽 70
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        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>
            男人添女人阴道视频 | 从解内衣开始吻戏床戏 | 国产菊爆视频在线观看 | 天天射天 | brazzersxxxxhd. | 干B网| 女生扣b视频 | 欧美另类综合 | 免费人成视频在线观看网站 | 成人性爱视频在线免费观看 |