<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【TS】825- 了不起的 TypeScript 入門教程

          共 27288字,需瀏覽 55分鐘

           ·

          2021-01-06 01:46


          創(chuàng)建了一個 “重學(xué)TypeScript” 的微信群,想加群的小伙伴,加我微信?"semlinker",備注重學(xué)TS。已出 TS 系列文章?39?篇。


          想學(xué)習(xí) TypeScript 的小伙伴看過來,本文將帶你一步步學(xué)習(xí) TypeScript 入門相關(guān)的十四個知識點,詳細(xì)的內(nèi)容大綱請看下圖:

          一、TypeScript 是什么

          TypeScript 是一種由微軟開發(fā)的自由和開源的編程語言。它是 JavaScript 的一個超集,而且本質(zhì)上向這個語言添加了可選的靜態(tài)類型和基于類的面向?qū)ο缶幊獭?/p>

          TypeScript 提供最新的和不斷發(fā)展的 JavaScript 特性,包括那些來自 2015 年的 ECMAScript 和未來的提案中的特性,比如異步功能和 Decorators,以幫助建立健壯的組件。下圖顯示了 TypeScript 與 ES5、ES2015 和 ES2016 之間的關(guān)系:

          1.1 TypeScript 與 JavaScript 的區(qū)別

          TypeScriptJavaScript
          JavaScript 的超集用于解決大型項目的代碼復(fù)雜性一種腳本語言,用于創(chuàng)建動態(tài)網(wǎng)頁。
          可以在編譯期間發(fā)現(xiàn)并糾正錯誤作為一種解釋型語言,只能在運行時發(fā)現(xiàn)錯誤
          強類型,支持靜態(tài)和動態(tài)類型弱類型,沒有靜態(tài)類型選項
          最終被編譯成 JavaScript 代碼,使瀏覽器可以理解可以直接在瀏覽器中使用
          支持模塊、泛型和接口不支持模塊,泛型或接口
          支持 ES3,ES4,ES5 和 ES6 等不支持編譯其他 ES3,ES4,ES5 或 ES6 功能
          社區(qū)的支持仍在增長,而且還不是很大大量的社區(qū)支持以及大量文檔和解決問題的支持

          1.2 獲取 TypeScript

          命令行的 TypeScript 編譯器可以使用 Node.js 包來安裝。

          1.安裝 TypeScript

          $?npm?install?-g?typescript

          2.編譯 TypeScript 文件

          $?tsc?helloworld.ts
          #?helloworld.ts?=>?helloworld.js

          當(dāng)然,對于剛?cè)腴T TypeScript 的小伙伴,也可以不用安裝 typescript,而是直接使用線上的 TypeScript Playground 來學(xué)習(xí)新的語法或新特性。

          TypeScript Playground:https://www.typescriptlang.org/play/

          二、TypeScript 基礎(chǔ)類型

          2.1 Boolean 類型

          let?isDone:?boolean?=?false;
          //?ES5:var?isDone?=?false;

          2.2 Number 類型

          let?count:?number?=?10;
          //?ES5:var?count?=?10;

          String 類型

          let?name:?string?=?"Semliker";
          //?ES5:var?name?=?'Semlinker';

          2.4 Array 類型

          let?list:?number[]?=?[1,?2,?3];
          //?ES5:var?list?=?[1,2,3];

          let?list:?Array<number>?=?[1,?2,?3];?//?Array泛型語法
          //?ES5:var?list?=?[1,2,3];

          2.5 Enum 類型

          使用枚舉我們可以定義一些帶名字的常量。 使用枚舉可以清晰地表達意圖或創(chuàng)建一組有區(qū)別的用例。 TypeScript 支持?jǐn)?shù)字的和基于字符串的枚舉。

          1.數(shù)字枚舉

          enum?Direction?{
          ??NORTH,
          ??SOUTH,
          ??EAST,
          ??WEST,
          }

          let?dir:?Direction?=?Direction.NORTH;

          默認(rèn)情況下,NORTH 的初始值為 0,其余的成員會從 1 開始自動增長。換句話說,Direction.SOUTH 的值為 1,Direction.EAST 的值為 2,Direction.WEST 的值為 3。上面的枚舉示例代碼經(jīng)過編譯后會生成以下代碼:

          "use?strict";
          var?Direction;
          (function?(Direction)?{
          ??Direction[(Direction["NORTH"]?=?0)]?=?"NORTH";
          ??Direction[(Direction["SOUTH"]?=?1)]?=?"SOUTH";
          ??Direction[(Direction["EAST"]?=?2)]?=?"EAST";
          ??Direction[(Direction["WEST"]?=?3)]?=?"WEST";
          })(Direction?||?(Direction?=?{}));
          var?dir?=?Direction.NORTH;

          當(dāng)然我們也可以設(shè)置 NORTH 的初始值,比如:

          enum?Direction?{
          ??NORTH?=?3,
          ??SOUTH,
          ??EAST,
          ??WEST,
          }

          2.字符串枚舉

          在 TypeScript 2.4 版本,允許我們使用字符串枚舉。在一個字符串枚舉里,每個成員都必須用字符串字面量,或另外一個字符串枚舉成員進行初始化。

          enum?Direction?{
          ??NORTH?=?"NORTH",
          ??SOUTH?=?"SOUTH",
          ??EAST?=?"EAST",
          ??WEST?=?"WEST",
          }

          3.異構(gòu)枚舉

          異構(gòu)枚舉的成員值是數(shù)字和字符串的混合:

          enum?Enum?{
          ??A,
          ??B,
          ??C?=?"C",
          ??D?=?"D",
          ??E?=?8,
          ??F,
          }

          2.6 Any 類型

          在 TypeScript 中,任何類型都可以被歸為 any 類型。這讓 any 類型成為了類型系統(tǒng)的頂級類型(也被稱作全局超級類型)。

          let?notSure:?any?=?666;
          notSure?=?"Semlinker";
          notSure?=?false;

          any 類型本質(zhì)上是類型系統(tǒng)的一個逃逸艙。作為開發(fā)者,這給了我們很大的自由:TypeScript 允許我們對 any 類型的值執(zhí)行任何操作,而無需事先執(zhí)行任何形式的檢查。比如:

          let?value:?any;

          value.foo.bar;?//?OK
          value.trim();?//?OK
          value();?//?OK
          new?value();?//?OK
          value[0][1];?//?OK

          在許多場景下,這太寬松了。使用 any 類型,可以很容易地編寫類型正確但在運行時有問題的代碼。如果我們使用 any 類型,就無法使用 TypeScript 提供的大量的保護機制。為了解決 any 帶來的問題,TypeScript 3.0 引入了 unknown 類型。

          2.7 Unknown 類型

          就像所有類型都可以賦值給 any,所有類型也都可以賦值給 unknown。這使得 unknown 成為 TypeScript 類型系統(tǒng)的另一種頂級類型(另一種是 any)。下面我們來看一下 unknown 類型的使用示例:

          let?value:?unknown;

          value?=?true;?//?OK
          value?=?42;?//?OK
          value?=?"Hello?World";?//?OK
          value?=?[];?//?OK
          value?=?{};?//?OK
          value?=?Math.random;?//?OK
          value?=?null;?//?OK
          value?=?undefined;?//?OK
          value?=?new?TypeError();?//?OK
          value?=?Symbol("type");?//?OK

          value 變量的所有賦值都被認(rèn)為是類型正確的。但是,當(dāng)我們嘗試將類型為 unknown 的值賦值給其他類型的變量時會發(fā)生什么?

          let?value:?unknown;

          let?value1:?unknown?=?value;?//?OK
          let?value2:?any?=?value;?//?OK
          let?value3:?boolean?=?value;?//?Error
          let?value4:?number?=?value;?//?Error
          let?value5:?string?=?value;?//?Error
          let?value6:?object?=?value;?//?Error
          let?value7:?any[]?=?value;?//?Error
          let?value8:?Function?=?value;?//?Error

          unknown 類型只能被賦值給 any 類型和 unknown 類型本身。直觀地說,這是有道理的:只有能夠保存任意類型值的容器才能保存 unknown 類型的值。畢竟我們不知道變量 value 中存儲了什么類型的值。

          現(xiàn)在讓我們看看當(dāng)我們嘗試對類型為 unknown 的值執(zhí)行操作時會發(fā)生什么。以下是我們在之前 any 章節(jié)看過的相同操作:

          let?value:?unknown;

          value.foo.bar;?//?Error
          value.trim();?//?Error
          value();?//?Error
          new?value();?//?Error
          value[0][1];?//?Error

          value 變量類型設(shè)置為 unknown 后,這些操作都不再被認(rèn)為是類型正確的。通過將 any 類型改變?yōu)?unknown 類型,我們已將允許所有更改的默認(rèn)設(shè)置,更改為禁止任何更改。

          2.8 Tuple 類型

          眾所周知,數(shù)組一般由同種類型的值組成,但有時我們需要在單個變量中存儲不同類型的值,這時候我們就可以使用元組。在 JavaScript 中是沒有元組的,元組是 TypeScript 中特有的類型,其工作方式類似于數(shù)組。

          元組可用于定義具有有限數(shù)量的未命名屬性的類型。每個屬性都有一個關(guān)聯(lián)的類型。使用元組時,必須提供每個屬性的值。為了更直觀地理解元組的概念,我們來看一個具體的例子:

          let?tupleType:?[string,?boolean];
          tupleType?=?["Semlinker",?true];

          在上面代碼中,我們定義了一個名為 tupleType 的變量,它的類型是一個類型數(shù)組 [string, boolean],然后我們按照正確的類型依次初始化 tupleType 變量。與數(shù)組一樣,我們可以通過下標(biāo)來訪問元組中的元素:

          console.log(tupleType[0]);?//?Semlinker
          console.log(tupleType[1]);?//?true

          在元組初始化的時候,如果出現(xiàn)類型不匹配的話,比如:

          tupleType?=?[true,?"Semlinker"];

          此時,TypeScript 編譯器會提示以下錯誤信息:

          [0]: Type 'true' is not assignable to type 'string'.
          [1]: Type 'string' is not assignable to type 'boolean'.

          很明顯是因為類型不匹配導(dǎo)致的。在元組初始化的時候,我們還必須提供每個屬性的值,不然也會出現(xiàn)錯誤,比如:

          tupleType?=?["Semlinker"];

          此時,TypeScript 編譯器會提示以下錯誤信息:

          Property?'1'?is?missing?in?type?'[string]'?but?required?in?type?'[string,?boolean]'.

          2.9 Void 類型

          某種程度上來說,void 類型像是與 any 類型相反,它表示沒有任何類型。當(dāng)一個函數(shù)沒有返回值時,你通常會見到其返回值類型是 void:

          //?聲明函數(shù)返回值為void
          function?warnUser():?void?{
          ??console.log("This?is?my?warning?message");
          }

          以上代碼編譯生成的 ES5 代碼如下:

          "use?strict";
          function?warnUser()?{
          ??console.log("This?is?my?warning?message");
          }

          需要注意的是,聲明一個 void 類型的變量沒有什么作用,因為它的值只能為 undefinednull

          let?unusable:?void?=?undefined;

          2.10 Null 和 Undefined 類型

          TypeScript 里,undefinednull 兩者有各自的類型分別為 undefinednull。

          let?u:?undefined?=?undefined;
          let?n:?null?=?null;

          默認(rèn)情況下 nullundefined 是所有類型的子類型。 就是說你可以把 nullundefined 賦值給 number 類型的變量。然而,如果你指定了--strictNullChecks 標(biāo)記,nullundefined 只能賦值給 void 和它們各自的類型。

          2.11 Never 類型

          never 類型表示的是那些永不存在的值的類型。 例如,never 類型是那些總是會拋出異?;蚋揪筒粫蟹祷刂档暮瘮?shù)表達式或箭頭函數(shù)表達式的返回值類型。

          //?返回never的函數(shù)必須存在無法達到的終點
          function?error(message:?string):?never?{
          ??throw?new?Error(message);
          }

          function?infiniteLoop():?never?{
          ??while?(true)?{}
          }

          在 TypeScript 中,可以利用 never 類型的特性來實現(xiàn)全面性檢查,具體示例如下:

          type?Foo?=?string?|?number;

          function?controlFlowAnalysisWithNever(foo:?Foo)?{
          ??if?(typeof?foo?===?"string")?{
          ????//?這里?foo?被收窄為?string?類型
          ??}?else?if?(typeof?foo?===?"number")?{
          ????//?這里?foo?被收窄為?number?類型
          ??}?else?{
          ????//?foo?在這里是?never
          ????const?check:?never?=?foo;
          ??}
          }

          三、TypeScript 斷言

          有時候你會遇到這樣的情況,你會比 TypeScript 更了解某個值的詳細(xì)信息。通常這會發(fā)生在你清楚地知道一個實體具有比它現(xiàn)有類型更確切的類型。

          通過類型斷言這種方式可以告訴編譯器,“相信我,我知道自己在干什么”。類型斷言好比其他語言里的類型轉(zhuǎn)換,但是不進行特殊的數(shù)據(jù)檢查和解構(gòu)。它沒有運行時的影響,只是在編譯階段起作用。

          類型斷言有兩種形式:

          3.1 “尖括號” 語法

          let?someValue:?any?=?"this?is?a?string";
          let?strLength:?number?=?(<string>someValue).length;

          3.2 as 語法

          let?someValue:?any?=?"this?is?a?string";
          let?strLength:?number?=?(someValue?as?string).length;

          四、類型守衛(wèi)

          A type guard is some expression that performs a runtime check that guarantees the type in some scope. —— TypeScript 官方文檔

          類型保護是可執(zhí)行運行時檢查的一種表達式,用于確保該類型在一定的范圍內(nèi)。換句話說,類型保護可以保證一個字符串是一個字符串,盡管它的值也可以是一個數(shù)值。類型保護與特性檢測并不是完全不同,其主要思想是嘗試檢測屬性、方法或原型,以確定如何處理值。目前主要有四種的方式來實現(xiàn)類型保護:

          4.1 in 關(guān)鍵字

          interface?Admin?{
          ??name:?string;
          ??privileges:?string[];
          }

          interface?Employee?{
          ??name:?string;
          ??startDate:?Date;
          }

          type?UnknownEmployee?=?Employee?|?Admin;

          function?printEmployeeInformation(emp:?UnknownEmployee)?{
          ??console.log("Name:?"?+?emp.name);
          ??if?("privileges"?in?emp)?{
          ????console.log("Privileges:?"?+?emp.privileges);
          ??}
          ??if?("startDate"?in?emp)?{
          ????console.log("Start?Date:?"?+?emp.startDate);
          ??}
          }

          4.2 typeof 關(guān)鍵字

          function?padLeft(value:?string,?padding:?string?|?number)?{
          ??if?(typeof?padding?===?"number")?{
          ??????return?Array(padding?+?1).join("?")?+?value;
          ??}
          ??if?(typeof?padding?===?"string")?{
          ??????return?padding?+?value;
          ??}
          ??throw?new?Error(`Expected?string?or?number,?got?'${padding}'.`);
          }

          typeof 類型保護只支持兩種形式:typeof v === "typename"typeof v !== typename"typename" 必須是 "number", "string", "boolean""symbol"。 但是 TypeScript 并不會阻止你與其它字符串比較,語言不會把那些表達式識別為類型保護。

          4.3 instanceof 關(guān)鍵字

          interface?Padder?{
          ??getPaddingString():?string;
          }

          class?SpaceRepeatingPadder?implements?Padder?{
          ??constructor(private?numSpaces:?number)?{}
          ??getPaddingString()?{
          ????return?Array(this.numSpaces?+?1).join("?");
          ??}
          }

          class?StringPadder?implements?Padder?{
          ??constructor(private?value:?string)?{}
          ??getPaddingString()?{
          ????return?this.value;
          ??}
          }

          let?padder:?Padder?=?new?SpaceRepeatingPadder(6);

          if?(padder?instanceof?SpaceRepeatingPadder)?{
          ??//?padder的類型收窄為?'SpaceRepeatingPadder'
          }

          4.4 自定義類型保護的類型謂詞

          function?isNumber(x:?any):?x?is?number?{
          ??return?typeof?x?===?"number";
          }

          function?isString(x:?any):?x?is?string?{
          ??return?typeof?x?===?"string";
          }

          五、聯(lián)合類型和類型別名

          5.1 聯(lián)合類型

          聯(lián)合類型通常與 nullundefined 一起使用:

          const?sayHello?=?(name:?string?|?undefined)?=>?{
          ??/*?...?*/
          };

          例如,這里 name 的類型是 string | undefined 意味著可以將 stringundefined 的值傳遞給sayHello 函數(shù)。

          sayHello("Semlinker");
          sayHello(undefined);

          通過這個示例,你可以憑直覺知道類型 A 和類型 B 聯(lián)合后的類型是同時接受 A 和 B 值的類型。

          5.2 可辨識聯(lián)合

          TypeScript 可辨識聯(lián)合(Discriminated Unions)類型,也稱為代數(shù)數(shù)據(jù)類型或標(biāo)簽聯(lián)合類型。它包含 3 個要點:可辨識、聯(lián)合類型和類型守衛(wèi)。

          這種類型的本質(zhì)是結(jié)合聯(lián)合類型和字面量類型的一種類型保護方法。如果一個類型是多個類型的聯(lián)合類型,且多個類型含有一個公共屬性,那么就可以利用這個公共屬性,來創(chuàng)建不同的類型保護區(qū)塊。

          1.可辨識

          可辨識要求聯(lián)合類型中的每個元素都含有一個單例類型屬性,比如:

          enum?CarTransmission?{
          ??Automatic?=?200,
          ??Manual?=?300
          }

          interface?Motorcycle?{
          ??vType:?"motorcycle";?//?discriminant
          ??make:?number;?//?year
          }

          interface?Car?{
          ??vType:?"car";?//?discriminant
          ??transmission:?CarTransmission
          }

          interface?Truck?{
          ??vType:?"truck";?//?discriminant
          ??capacity:?number;?//?in?tons
          }

          在上述代碼中,我們分別定義了 Motorcycle、 CarTruck 三個接口,在這些接口中都包含一個 vType 屬性,該屬性被稱為可辨識的屬性,而其它的屬性只跟特性的接口相關(guān)。

          2.聯(lián)合類型

          基于前面定義了三個接口,我們可以創(chuàng)建一個 Vehicle 聯(lián)合類型:

          type?Vehicle?=?Motorcycle?|?Car?|?Truck;

          現(xiàn)在我們就可以開始使用 Vehicle 聯(lián)合類型,對于 Vehicle 類型的變量,它可以表示不同類型的車輛。

          3.類型守衛(wèi)

          下面我們來定義一個 evaluatePrice 方法,該方法用于根據(jù)車輛的類型、容量和評估因子來計算價格,具體實現(xiàn)如下:

          const?EVALUATION_FACTOR?=?Math.PI;?
          function?evaluatePrice(vehicle:?Vehicle)?{
          ??return?vehicle.capacity?*?EVALUATION_FACTOR;
          }

          const?myTruck:?Truck?=?{?vType:?"truck",?capacity:?9.5?};
          evaluatePrice(myTruck);

          對于以上代碼,TypeScript 編譯器將會提示以下錯誤信息:

          Property 'capacity' does not exist on type 'Vehicle'.
          Property 'capacity' does not exist on type 'Motorcycle'.

          原因是在 Motorcycle 接口中,并不存在 capacity 屬性,而對于 Car 接口來說,它也不存在 capacity 屬性。那么,現(xiàn)在我們應(yīng)該如何解決以上問題呢?這時,我們可以使用類型守衛(wèi)。下面我們來重構(gòu)一下前面定義的 evaluatePrice 方法,重構(gòu)后的代碼如下:

          function?evaluatePrice(vehicle:?Vehicle)?{
          ??switch(vehicle.vType)?{
          ????case?"car":
          ??????return?vehicle.transmission?*?EVALUATION_FACTOR;
          ????case?"truck":
          ??????return?vehicle.capacity?*?EVALUATION_FACTOR;
          ????case?"motorcycle":
          ??????return?vehicle.make?*?EVALUATION_FACTOR;
          ??}
          }

          在以上代碼中,我們使用 switchcase 運算符來實現(xiàn)類型守衛(wèi),從而確保在 evaluatePrice 方法中,我們可以安全地訪問 vehicle 對象中的所包含的屬性,來正確的計算該車輛類型所對應(yīng)的價格。

          5.3 類型別名

          類型別名用來給一個類型起個新名字。

          type?Message?=?string?|?string[];

          let?greet?=?(message:?Message)?=>?{
          ??//?...
          };

          六、交叉類型

          TypeScript 交叉類型是將多個類型合并為一個類型。 這讓我們可以把現(xiàn)有的多種類型疊加到一起成為一種類型,它包含了所需的所有類型的特性。

          interface?IPerson?{
          ??id:?string;
          ??age:?number;
          }

          interface?IWorker?{
          ??companyId:?string;
          }

          type?IStaff?=?IPerson?&?IWorker;

          const?staff:?IStaff?=?{
          ??id:?'E1006',
          ??age:?33,
          ??companyId:?'EFT'
          };

          console.dir(staff)

          在上面示例中,我們首先為 IPerson 和 IWorker 類型定義了不同的成員,然后通過 & 運算符定義了 IStaff ?交叉類型,所以該類型同時擁有 IPerson 和 IWorker 這兩種類型的成員。

          七、TypeScript 函數(shù)

          7.1 TypeScript 函數(shù)與 JavaScript 函數(shù)的區(qū)別

          TypeScriptJavaScript
          含有類型無類型
          箭頭函數(shù)箭頭函數(shù)(ES2015)
          函數(shù)類型無函數(shù)類型
          必填和可選參數(shù)所有參數(shù)都是可選的
          默認(rèn)參數(shù)默認(rèn)參數(shù)
          剩余參數(shù)剩余參數(shù)
          函數(shù)重載無函數(shù)重載

          7.2 箭頭函數(shù)

          1.常見語法

          myBooks.forEach(()?=>?console.log('reading'));

          myBooks.forEach(title?=>?console.log(title));

          myBooks.forEach((title,?idx,?arr)?=>
          ??console.log(idx?+?'-'?+?title);
          );

          myBooks.forEach((title,?idx,?arr)?=>?{
          ??console.log(idx?+?'-'?+?title);
          });

          2.使用示例

          //?未使用箭頭函數(shù)
          function?Book()?{
          ??let?self?=?this;
          ??self.publishDate?=?2016;
          ??setInterval(function?()?{
          ????console.log(self.publishDate);
          ??},?1000);
          }

          //?使用箭頭函數(shù)
          function?Book()?{
          ??this.publishDate?=?2016;
          ??setInterval(()?=>?{
          ????console.log(this.publishDate);
          ??},?1000);
          }

          7.3 參數(shù)類型和返回類型

          function?createUserId(name:?string,?id:?number):?string?{
          ??return?name?+?id;
          }

          7.4 函數(shù)類型

          let?IdGenerator:?(chars:?string,?nums:?number)?=>?string;

          function?createUserId(name:?string,?id:?number):?string?{
          ??return?name?+?id;
          }

          IdGenerator?=?createUserId;

          7.5 可選參數(shù)及默認(rèn)參數(shù)

          //?可選參數(shù)
          function?createUserId(name:?string,?age?:?number,?id:?number):?string?{
          ??return?name?+?id;
          }

          //?默認(rèn)參數(shù)
          function?createUserId(
          ??name:?string?=?"Semlinker",
          ??age?:?number,
          ??id:?number
          ):?string?
          {
          ??return?name?+?id;
          }

          7.6 剩余參數(shù)

          function?push(array,?...items)?{
          ??items.forEach(function?(item)?{
          ????array.push(item);
          ??});
          }

          let?a?=?[];
          push(a,?1,?2,?3);

          7.7 函數(shù)重載

          函數(shù)重載或方法重載是使用相同名稱和不同參數(shù)數(shù)量或類型創(chuàng)建多個方法的一種能力。要解決前面遇到的問題,方法就是為同一個函數(shù)提供多個函數(shù)類型定義來進行函數(shù)重載,編譯器會根據(jù)這個列表去處理函數(shù)的調(diào)用。

          function?add(a:?number,?b:?number):?number;
          function?add(a:?string,?b:?string):?string;
          function?add(a:?string,?b:?number):?string;
          function?add(a:?number,?b:?string):?string;
          function?add(a:?Combinable,?b:?Combinable)?{
          ??if?(typeof?a?===?"string"?||?typeof?b?===?"string")?{
          ????return?a.toString()?+?b.toString();
          ??}
          ??return?a?+?b;
          }

          在以上代碼中,我們?yōu)?add 函數(shù)提供了多個函數(shù)類型定義,從而實現(xiàn)函數(shù)的重載。之后,可惡的錯誤消息又消失了,因為這時 result 變量的類型是 string 類型。在 TypeScript 中除了可以重載普通函數(shù)之外,我們還可以重載類中的成員方法。

          方法重載是指在同一個類中方法同名,參數(shù)不同(參數(shù)類型不同、參數(shù)個數(shù)不同或參數(shù)個數(shù)相同時參數(shù)的先后順序不同),調(diào)用時根據(jù)實參的形式,選擇與它匹配的方法執(zhí)行操作的一種技術(shù)。所以類中成員方法滿足重載的條件是:在同一個類中,方法名相同且參數(shù)列表不同。下面我們來舉一個成員方法重載的例子:

          class?Calculator?{
          ??add(a:?number,?b:?number):?number;
          ??add(a:?string,?b:?string):?string;
          ??add(a:?string,?b:?number):?string;
          ??add(a:?number,?b:?string):?string;
          ??add(a:?Combinable,?b:?Combinable)?{
          ????if?(typeof?a?===?"string"?||?typeof?b?===?"string")?{
          ??????return?a.toString()?+?b.toString();
          ????}
          ????return?a?+?b;
          ??}
          }

          const?calculator?=?new?Calculator();
          const?result?=?calculator.add("Semlinker",?"?Kakuqo");

          這里需要注意的是,當(dāng) TypeScript 編譯器處理函數(shù)重載時,它會查找重載列表,嘗試使用第一個重載定義。 如果匹配的話就使用這個。 因此,在定義重載的時候,一定要把最精確的定義放在最前面。另外在 Calculator 類中,add(a: Combinable, b: Combinable){ } 并不是重載列表的一部分,因此對于 add 成員方法來說,我們只定義了四個重載方法。

          八、TypeScript 數(shù)組

          8.1 數(shù)組解構(gòu)

          let?x:?number;?let?y:?number?;let?z:?number;
          let?five_array?=?[0,1,2,3,4];
          [x,y,z]?=?five_array;

          8.2 數(shù)組展開運算符

          let?two_array?=?[0,?1];
          let?five_array?=?[...two_array,?2,?3,?4];

          8.3 數(shù)組遍歷

          let?colors:?string[]?=?["red",?"green",?"blue"];
          for?(let?i?of?colors)?{
          ??console.log(i);
          }

          九、TypeScript 對象

          9.1 對象解構(gòu)

          let?person?=?{
          ??name:?"Semlinker",
          ??gender:?"Male",
          };

          let?{?name,?gender?}?=?person;

          9.2 對象展開運算符

          let?person?=?{
          ??name:?"Semlinker",
          ??gender:?"Male",
          ??address:?"Xiamen",
          };

          //?組裝對象
          let?personWithAge?=?{?...person,?age:?33?};

          //?獲取除了某些項外的其它項
          let?{?name,?...rest?}?=?person;

          十、TypeScript 接口

          在面向?qū)ο笳Z言中,接口是一個很重要的概念,它是對行為的抽象,而具體如何行動需要由類去實現(xiàn)。

          TypeScript 中的接口是一個非常靈活的概念,除了可用于對類的一部分行為進行抽象以外,也常用于對「對象的形狀(Shape)」進行描述。

          10.1 對象的形狀

          interface?Person?{
          ??name:?string;
          ??age:?number;
          }

          let?Semlinker:?Person?=?{
          ??name:?"Semlinker",
          ??age:?33,
          };

          10.2 可選 | 只讀屬性

          interface?Person?{
          ??readonly?name:?string;
          ??age?:?number;
          }

          只讀屬性用于限制只能在對象剛剛創(chuàng)建的時候修改其值。此外 TypeScript 還提供了 ReadonlyArray 類型,它與 Array 相似,只是把所有可變方法去掉了,因此可以確保數(shù)組創(chuàng)建后再也不能被修改。

          let?a:?number[]?=?[1,?2,?3,?4];
          let?ro:?ReadonlyArray<number>?=?a;
          ro[0]?=?12;?//?error!
          ro.push(5);?//?error!
          ro.length?=?100;?//?error!
          a?=?ro;?//?error!

          十一、TypeScript 類

          11.1 類的屬性與方法

          在面向?qū)ο笳Z言中,類是一種面向?qū)ο笥嬎銠C編程語言的構(gòu)造,是創(chuàng)建對象的藍圖,描述了所創(chuàng)建的對象共同的屬性和方法。

          在 TypeScript 中,我們可以通過 Class 關(guān)鍵字來定義一個類:

          class?Greeter?{
          ??//?靜態(tài)屬性
          ??static?cname:?string?=?"Greeter";
          ??//?成員屬性
          ??greeting:?string;

          ??//?構(gòu)造函數(shù)?-?執(zhí)行初始化操作
          ??constructor(message:?string)?{
          ????this.greeting?=?message;
          ??}

          ??//?靜態(tài)方法
          ??static?getClassName()?{
          ????return?"Class?name?is?Greeter";
          ??}

          ??//?成員方法
          ??greet()?{
          ????return?"Hello,?"?+?this.greeting;
          ??}
          }

          let?greeter?=?new?Greeter("world");

          那么成員屬性與靜態(tài)屬性,成員方法與靜態(tài)方法有什么區(qū)別呢?這里無需過多解釋,我們直接看一下以下編譯生成的 ES5 代碼:

          "use?strict";
          var?Greeter?=?/**?@class?*/?(function?()?{
          ????//?構(gòu)造函數(shù)?-?執(zhí)行初始化操作
          ????function?Greeter(message)?{
          ????????this.greeting?=?message;
          ????}
          ????//?靜態(tài)方法
          ????Greeter.getClassName?=?function?()?{
          ????????return?"Class?name?is?Greeter";
          ????};
          ????//?成員方法
          ????Greeter.prototype.greet?=?function?()?{
          ????????return?"Hello,?"?+?this.greeting;
          ????};
          ????//?靜態(tài)屬性
          ????Greeter.cname?=?"Greeter";
          ????return?Greeter;
          }());
          var?greeter?=?new?Greeter("world");

          11.2 訪問器

          在 TypeScript 中,我們可以通過 gettersetter 方法來實現(xiàn)數(shù)據(jù)的封裝和有效性校驗,防止出現(xiàn)異常數(shù)據(jù)。

          let?passcode?=?"Hello?TypeScript";

          class?Employee?{
          ??private?_fullName:?string;

          ??get?fullName():?string?{
          ????return?this._fullName;
          ??}

          ??set?fullName(newName:?string)?{
          ????if?(passcode?&&?passcode?==?"Hello?TypeScript")?{
          ??????this._fullName?=?newName;
          ????}?else?{
          ??????console.log("Error:?Unauthorized?update?of?employee!");
          ????}
          ??}
          }

          let?employee?=?new?Employee();
          employee.fullName?=?"Semlinker";
          if?(employee.fullName)?{
          ??console.log(employee.fullName);
          }

          11.3 類的繼承

          繼承 (Inheritance) 是一種聯(lián)結(jié)類與類的層次模型。指的是一個類(稱為子類、子接口)繼承另外的一個類(稱為父類、父接口)的功能,并可以增加它自己的新功能的能力,繼承是類與類或者接口與接口之間最常見的關(guān)系。

          繼承是一種 is-a 關(guān)系:

          在 TypeScript 中,我們可以通過 extends 關(guān)鍵字來實現(xiàn)繼承:

          class?Animal?{
          ??name:?string;
          ??constructor(theName:?string)?{
          ????this.name?=?theName;
          ??}
          ??move(distanceInMeters:?number?=?0)?{
          ????console.log(`${this.name}?moved?${distanceInMeters}m.`);
          ??}
          }

          class?Snake?extends?Animal?{
          ??constructor(name:?string)?{
          ????super(name);
          ??}
          ??move(distanceInMeters?=?5)?{
          ????console.log("Slithering...");
          ????super.move(distanceInMeters);
          ??}
          }

          let?sam?=?new?Snake("Sammy?the?Python");
          sam.move();

          11.4 ECMAScript 私有字段

          在 TypeScript 3.8 版本就開始支持ECMAScript 私有字段,使用方式如下:

          class?Person?{
          ??#name:?string;

          ??constructor(name:?string)?{
          ????this.#name?=?name;
          ??}

          ??greet()?{
          ????console.log(`Hello,?my?name?is?${this.#name}!`);
          ??}
          }

          let?semlinker?=?new?Person("Semlinker");

          semlinker.#name;
          //?????~~~~~
          //?Property?'#name'?is?not?accessible?outside?class?'Person'
          //?because?it?has?a?private?identifier.

          與常規(guī)屬性(甚至使用 private 修飾符聲明的屬性)不同,私有字段要牢記以下規(guī)則:

          • 私有字段以 # 字符開頭,有時我們稱之為私有名稱;
          • 每個私有字段名稱都唯一地限定于其包含的類;
          • 不能在私有字段上使用 TypeScript 可訪問性修飾符(如 public 或 private);
          • 私有字段不能在包含的類之外訪問,甚至不能被檢測到。

          十二、TypeScript 泛型

          軟件工程中,我們不僅要創(chuàng)建一致的定義良好的 API,同時也要考慮可重用性。 組件不僅能夠支持當(dāng)前的數(shù)據(jù)類型,同時也能支持未來的數(shù)據(jù)類型,這在創(chuàng)建大型系統(tǒng)時為你提供了十分靈活的功能。

          在像 C# 和 Java 這樣的語言中,可以使用泛型來創(chuàng)建可重用的組件,一個組件可以支持多種類型的數(shù)據(jù)。 這樣用戶就可以以自己的數(shù)據(jù)類型來使用組件。

          設(shè)計泛型的關(guān)鍵目的是在成員之間提供有意義的約束,這些成員可以是:類的實例成員、類的方法、函數(shù)參數(shù)和函數(shù)返回值。

          泛型(Generics)是允許同一個函數(shù)接受不同類型參數(shù)的一種模板。相比于使用 any 類型,使用泛型來創(chuàng)建可復(fù)用的組件要更好,因為泛型會保留參數(shù)類型。

          12.1 泛型接口

          interface?GenericIdentityFn?{
          ??(arg:?T):?T;
          }

          12.2 泛型類

          class?GenericNumber?{
          ??zeroValue:?T;
          ??add:?(x:?T,?y:?T)?=>?T;
          }

          let?myGenericNumber?=?new?GenericNumber<number>();
          myGenericNumber.zeroValue?=?0;
          myGenericNumber.add?=?function?(x,?y)?{
          ??return?x?+?y;
          };

          12.3 泛型變量

          對剛接觸 TypeScript 泛型的小伙伴來說,看到 T 和 E,還有 K 和 V 這些泛型變量時,估計會一臉懵逼。其實這些大寫字母并沒有什么本質(zhì)的區(qū)別,只不過是一個約定好的規(guī)范而已。也就是說使用大寫字母 A-Z 定義的類型變量都屬于泛型,把 T 換成 A,也是一樣的。下面我們介紹一下一些常見泛型變量代表的意思:

          • T(Type):表示一個 TypeScript 類型
          • K(Key):表示對象中的鍵類型
          • V(Value):表示對象中的值類型
          • E(Element):表示元素類型

          12.4 泛型工具類型

          為了方便開發(fā)者 TypeScript 內(nèi)置了一些常用的工具類型,比如 Partial、Required、Readonly、Record 和 ReturnType 等。出于篇幅考慮,這里我們只簡單介紹 Partial 工具類型。不過在具體介紹之前,我們得先介紹一些相關(guān)的基礎(chǔ)知識,方便讀者自行學(xué)習(xí)其它的工具類型。

          1.typeof

          在 TypeScript 中,typeof 操作符可以用來獲取一個變量聲明或?qū)ο蟮念愋汀?/p>

          interface?Person?{
          ??name:?string;
          ??age:?number;
          }

          const?sem:?Person?=?{?name:?'semlinker',?age:?30?};
          type?Sem=?typeof?sem;?//?->?Person

          function?toArray(x:?number):?Array<number>?{
          ??return?[x];
          }

          type?Func?=?typeof?toArray;?//?->?(x:?number)?=>?number[]

          2.keyof

          keyof 操作符可以用來一個對象中的所有 key 值:

          interface?Person?{
          ????name:?string;
          ????age:?number;
          }

          type?K1?=?keyof?Person;?//?"name"?|?"age"
          type?K2?=?keyof?Person[];?//?"length"?|?"toString"?|?"pop"?|?"push"?|?"concat"?|?"join"?
          type?K3?=?keyof?{?[x:?string]:?Person?};??//?string?|?number

          3.in

          in 用來遍歷枚舉類型:

          type?Keys?=?"a"?|?"b"?|?"c"

          type?Obj?=??{
          ??[p?in?Keys]:?any
          }?//?->?{?a:?any,?b:?any,?c:?any?}

          4.infer

          在條件類型語句中,可以用 infer 聲明一個類型變量并且對它進行使用。

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

          以上代碼中 infer R 就是聲明一個變量來承載傳入函數(shù)簽名的返回值類型,簡單說就是用它取到函數(shù)返回值的類型方便之后使用。

          5.extends

          有時候我們定義的泛型不想過于靈活或者說想繼承某些類等,可以通過 extends 關(guān)鍵字添加泛型約束。

          interface?ILengthwise?{
          ??length:?number;
          }

          function?loggingIdentity<T?extends?ILengthwise>(arg:?T):?T?{
          ??console.log(arg.length);
          ??return?arg;
          }

          現(xiàn)在這個泛型函數(shù)被定義了約束,因此它不再是適用于任意類型:

          loggingIdentity(3);??//?Error,?number?doesn't?have?a?.length?property

          這時我們需要傳入符合約束類型的值,必須包含必須的屬性:

          loggingIdentity({length:?10,?value:?3});

          6.Partial

          Partial 的作用就是將某個類型里的屬性全部變?yōu)榭蛇x項 ?。

          定義:

          /**
          ?*?node_modules/typescript/lib/lib.es5.d.ts
          ?*?Make?all?properties?in?T?optional
          ?*/

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

          在以上代碼中,首先通過 keyof T 拿到 T 的所有屬性名,然后使用 in 進行遍歷,將值賦給 P,最后通過 T[P] 取得相應(yīng)的屬性值。中間的 ? 號,用于將所有屬性變?yōu)榭蛇x。

          示例:

          interface?Todo?{
          ??title:?string;
          ??description:?string;
          }

          function?updateTodo(todo:?Todo,?fieldsToUpdate:?Partial)?{
          ??return?{?...todo,?...fieldsToUpdate?};
          }

          const?todo1?=?{
          ??title:?"organize?desk",
          ??description:?"clear?clutter",
          };

          const?todo2?=?updateTodo(todo1,?{
          ??description:?"throw?out?trash",
          });

          在上面的 updateTodo 方法中,我們利用 Partial 工具類型,定義 fieldsToUpdate 的類型為 Partial,即:

          {
          ???title?:?string?|?undefined;
          ???description?:?string?|?undefined;
          }

          十三、TypeScript 裝飾器

          13.1 裝飾器是什么

          • 它是一個表達式
          • 該表達式被執(zhí)行后,返回一個函數(shù)
          • 函數(shù)的入?yún)⒎謩e為 target、name 和 descriptor
          • 執(zhí)行該函數(shù)后,可能返回 descriptor 對象,用于配置 target 對象

          13.2 裝飾器的分類

          • 類裝飾器(Class decorators)
          • 屬性裝飾器(Property decorators)
          • 方法裝飾器(Method decorators)
          • 參數(shù)裝飾器(Parameter decorators)

          13.3 類裝飾器

          類裝飾器聲明:

          declare?type?ClassDecorator?=?extends?Function>(
          ??target:?TFunction
          )?=>?TFunction?|?void;

          類裝飾器顧名思義,就是用來裝飾類的。它接收一個參數(shù):

          • target: TFunction - 被裝飾的類

          看完第一眼后,是不是感覺都不好了。沒事,我們馬上來個例子:

          function?Greeter(target:?Function):?void?{
          ??target.prototype.greet?=?function?():?void?{
          ????console.log("Hello?Semlinker!");
          ??};
          }

          @Greeter
          class?Greeting?{
          ??constructor()?{
          ????//?內(nèi)部實現(xiàn)
          ??}
          }

          let?myGreeting?=?new?Greeting();
          myGreeting.greet();?//?console?output:?'Hello?Semlinker!';

          上面的例子中,我們定義了 Greeter 類裝飾器,同時我們使用了 @Greeter 語法糖,來使用裝飾器。

          友情提示:讀者可以直接復(fù)制上面的代碼,在 TypeScript Playground 中運行查看結(jié)果。

          有的讀者可能想問,例子中總是輸出 Hello Semlinker! ,能自定義輸出的問候語么 ?這個問題很好,答案是可以的。

          具體實現(xiàn)如下:

          function?Greeter(greeting:?string)?{
          ??return?function?(target:?Function)?{
          ????target.prototype.greet?=?function?():?void?{
          ??????console.log(greeting);
          ????};
          ??};
          }

          @Greeter("Hello?TS!")
          class?Greeting?{
          ??constructor()?{
          ????//?內(nèi)部實現(xiàn)
          ??}
          }

          let?myGreeting?=?new?Greeting();
          myGreeting.greet();?//?console?output:?'Hello?TS!';

          13.4 屬性裝飾器

          屬性裝飾器聲明:

          declare?type?PropertyDecorator?=?(target:Object,?
          ??propertyKey:?string?|?symbol?)?=>?void;

          屬性裝飾器顧名思義,用來裝飾類的屬性。它接收兩個參數(shù):

          • target: Object - 被裝飾的類
          • propertyKey: string | symbol - 被裝飾類的屬性名

          趁熱打鐵,馬上來個例子熱熱身:

          function?logProperty(target:?any,?key:?string)?{
          ??delete?target[key];

          ??const?backingField?=?"_"?+?key;

          ??Object.defineProperty(target,?backingField,?{
          ????writable:?true,
          ????enumerable:?true,
          ????configurable:?true
          ??});

          ??//?property?getter
          ??const?getter?=?function?(this:?any)?{
          ????const?currVal?=?this[backingField];
          ????console.log(`Get:?${key}?=>?${currVal}`);
          ????return?currVal;
          ??};

          ??//?property?setter
          ??const?setter?=?function?(this:?any,?newVal:?any)?{
          ????console.log(`Set:?${key}?=>?${newVal}`);
          ????this[backingField]?=?newVal;
          ??};

          ??//?Create?new?property?with?getter?and?setter
          ??Object.defineProperty(target,?key,?{
          ????get:?getter,
          ????set:?setter,
          ????enumerable:?true,
          ????configurable:?true
          ??});
          }

          class?Person?{?
          ??@logProperty
          ??public?name:?string;

          ??constructor(name?:?string)?{?
          ????this.name?=?name;
          ??}
          }

          const?p1?=?new?Person("semlinker");
          p1.name?=?"kakuqo";

          以上代碼我們定義了一個 logProperty 函數(shù),來跟蹤用戶對屬性的操作,當(dāng)代碼成功運行后,在控制臺會輸出以下結(jié)果:

          Set: name => semlinker
          Set: name => kakuqo

          13.5 方法裝飾器

          方法裝飾器聲明:

          declare?type?MethodDecorator?=?(target:Object,?propertyKey:?string?|?symbol,????
          ??descriptor:?TypePropertyDescript)?=>?TypedPropertyDescriptor?|?void;

          方法裝飾器顧名思義,用來裝飾類的方法。它接收三個參數(shù):

          • target: Object - 被裝飾的類
          • propertyKey: string | symbol - 方法名
          • descriptor: TypePropertyDescript - 屬性描述符

          廢話不多說,直接上例子:

          function?LogOutput(tarage:?Function,?key:?string,?descriptor:?any)?{
          ??let?originalMethod?=?descriptor.value;
          ??let?newMethod?=?function(...args:?any[]):?any?{
          ????let?result:?any?=?originalMethod.apply(this,?args);
          ????if(!this.loggedOutput)?{
          ??????this.loggedOutput?=?new?Array<any>();
          ????}
          ????this.loggedOutput.push({
          ??????method:?key,
          ??????parameters:?args,
          ??????output:?result,
          ??????timestamp:?new?Date()
          ????});
          ????return?result;
          ??};
          ??descriptor.value?=?newMethod;
          }

          class?Calculator?{
          ??@LogOutput
          ??double?(num:?number):?number?{
          ????return?num?*?2;
          ??}
          }

          let?calc?=?new?Calculator();
          calc.double(11);
          //?console?ouput:?[{method:?"double",?output:?22,?...}]
          console.log(calc.loggedOutput);?

          下面我們來介紹一下參數(shù)裝飾器。

          13.6 參數(shù)裝飾器

          參數(shù)裝飾器聲明:

          declare?type?ParameterDecorator?=?(target:?Object,?propertyKey:?string?|?symbol,?
          ??parameterIndex:?number?)?=>?void

          參數(shù)裝飾器顧名思義,是用來裝飾函數(shù)參數(shù),它接收三個參數(shù):

          • target: Object - 被裝飾的類
          • propertyKey: string | symbol - 方法名
          • parameterIndex: number - 方法中參數(shù)的索引值
          function?Log(target:?Function,?key:?string,?parameterIndex:?number)?{
          ??let?functionLogged?=?key?||?target.prototype.constructor.name;
          ??console.log(`The?parameter?in?position?${parameterIndex}?at?${functionLogged}?has
          ?been?decorated`
          );
          }

          class?Greeter?{
          ??greeting:?string;
          ??constructor(@Log?phrase:?string)?{
          ?this.greeting?=?phrase;?
          ??}
          }

          //?console?output:?The?parameter?in?position?0?
          //?at?Greeter?has?been?decorated

          介紹完 TypeScript 入門相關(guān)的基礎(chǔ)知識,猜測很多剛?cè)腴T的小伙伴已有 “從入門到放棄” 的想法,最后我們來簡單介紹一下編譯上下文。

          十四、編譯上下文

          14.1 tsconfig.json 的作用

          • 用于標(biāo)識 TypeScript 項目的根路徑;
          • 用于配置 TypeScript 編譯器;
          • 用于指定編譯的文件。

          14.2 tsconfig.json 重要字段

          • files - 設(shè)置要編譯的文件的名稱;
          • include - 設(shè)置需要進行編譯的文件,支持路徑模式匹配;
          • exclude - 設(shè)置無需進行編譯的文件,支持路徑模式匹配;
          • compilerOptions - 設(shè)置與編譯流程相關(guān)的選項。

          14.3 compilerOptions 選項

          compilerOptions 支持很多選項,常見的有 baseUrl、 target、baseUrl、 moduleResolutionlib 等。

          compilerOptions 每個選項的詳細(xì)說明如下:

          {
          ??"compilerOptions":?{

          ????/*?基本選項?*/
          ????"target":?"es5",???????????????????????//?指定?ECMAScript?目標(biāo)版本:?'ES3'?(default),?'ES5',?'ES6'/'ES2015',?'ES2016',?'ES2017',?or?'ESNEXT'
          ????"module":?"commonjs",??????????????????//?指定使用模塊:?'commonjs',?'amd',?'system',?'umd'?or?'es2015'
          ????"lib":?[],?????????????????????????????//?指定要包含在編譯中的庫文件
          ????"allowJs":?true,???????????????????????//?允許編譯?javascript?文件
          ????"checkJs":?true,???????????????????????//?報告?javascript?文件中的錯誤
          ????"jsx":?"preserve",?????????????????????//?指定?jsx?代碼的生成:?'preserve',?'react-native',?or?'react'
          ????"declaration":?true,???????????????????//?生成相應(yīng)的?'.d.ts'?文件
          ????"sourceMap":?true,?????????????????????//?生成相應(yīng)的?'.map'?文件
          ????"outFile":?"./",???????????????????????//?將輸出文件合并為一個文件
          ????"outDir":?"./",????????????????????????//?指定輸出目錄
          ????"rootDir":?"./",???????????????????????//?用來控制輸出目錄結(jié)構(gòu)?--outDir.
          ????"removeComments":?true,????????????????//?刪除編譯后的所有的注釋
          ????"noEmit":?true,????????????????????????//?不生成輸出文件
          ????"importHelpers":?true,?????????????????//?從?tslib?導(dǎo)入輔助工具函數(shù)
          ????"isolatedModules":?true,???????????????//?將每個文件做為單獨的模塊?(與?'ts.transpileModule'?類似).

          ????/*?嚴(yán)格的類型檢查選項?*/
          ????"strict":?true,????????????????????????//?啟用所有嚴(yán)格類型檢查選項
          ????"noImplicitAny":?true,?????????????????//?在表達式和聲明上有隱含的?any類型時報錯
          ????"strictNullChecks":?true,??????????????//?啟用嚴(yán)格的?null?檢查
          ????"noImplicitThis":?true,????????????????//?當(dāng)?this?表達式值為?any?類型的時候,生成一個錯誤
          ????"alwaysStrict":?true,??????????????????//?以嚴(yán)格模式檢查每個模塊,并在每個文件里加入?'use?strict'

          ????/*?額外的檢查?*/
          ????"noUnusedLocals":?true,????????????????//?有未使用的變量時,拋出錯誤
          ????"noUnusedParameters":?true,????????????//?有未使用的參數(shù)時,拋出錯誤
          ????"noImplicitReturns":?true,?????????????//?并不是所有函數(shù)里的代碼都有返回值時,拋出錯誤
          ????"noFallthroughCasesInSwitch":?true,????//?報告?switch?語句的?fallthrough?錯誤。(即,不允許?switch?的?case?語句貫穿)

          ????/*?模塊解析選項?*/
          ????"moduleResolution":?"node",????????????//?選擇模塊解析策略:?'node'?(Node.js)?or?'classic'?(TypeScript?pre-1.6)
          ????"baseUrl":?"./",???????????????????????//?用于解析非相對模塊名稱的基目錄
          ????"paths":?{},???????????????????????????//?模塊名到基于?baseUrl?的路徑映射的列表
          ????"rootDirs":?[],????????????????????????//?根文件夾列表,其組合內(nèi)容表示項目運行時的結(jié)構(gòu)內(nèi)容
          ????"typeRoots":?[],???????????????????????//?包含類型聲明的文件列表
          ????"types":?[],???????????????????????????//?需要包含的類型聲明文件名列表
          ????"allowSyntheticDefaultImports":?true,??//?允許從沒有設(shè)置默認(rèn)導(dǎo)出的模塊中默認(rèn)導(dǎo)入。

          ????/*?Source?Map?Options?*/
          ????"sourceRoot":?"./",????????????????????//?指定調(diào)試器應(yīng)該找到?TypeScript?文件而不是源文件的位置
          ????"mapRoot":?"./",???????????????????????//?指定調(diào)試器應(yīng)該找到映射文件而不是生成文件的位置
          ????"inlineSourceMap":?true,???????????????//?生成單個?soucemaps?文件,而不是將?sourcemaps?生成不同的文件
          ????"inlineSources":?true,?????????????????//?將代碼與?sourcemaps?生成到一個文件中,要求同時設(shè)置了?--inlineSourceMap?或?--sourceMap?屬性

          ????/*?其他選項?*/
          ????"experimentalDecorators":?true,????????//?啟用裝飾器
          ????"emitDecoratorMetadata":?true??????????//?為裝飾器提供元數(shù)據(jù)的支持
          ??}
          }

          看到這里的讀者都是“真愛”,如果你還意猶未盡,那就來看看本人整理的 Github 上 1.5K+ 的開源項目:awesome-typescript。

          https://github.com/semlinker/awesome-typescript

          十五、參考資源

          • mariusschulz - the-unknown-type-in-typescript
          • 深入理解 TypeScript - 編譯上下文


          聚焦全棧,專注分享 Angular、TypeScript、Node.js 、Spring 技術(shù)棧等全棧干貨。



          回復(fù)?0?進入重學(xué)TypeScript學(xué)習(xí)群


          回復(fù)?1?獲取全棧修仙之路博客地址

          瀏覽 36
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  韩国三级黄 | 国产高清无码视频在线 | 日韩美女黄网站 | AV-ThePorn | 久久久久久久久成人电影 |