<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>

          Typescript真香秘笈

          共 18465字,需瀏覽 37分鐘

           ·

          2021-01-06 00:25

          本文由?IMWeb?首發(fā)于 IMWeb 社區(qū)網(wǎng)站 imweb.io。點(diǎn)擊閱讀原文查看 IMWeb 社區(qū)更多精彩文章。

          1. 前言

          2018年Stack Overflow Developer的調(diào)研(https://insights.stackoverflow.com/survey/2018/)顯示,TypeScript已經(jīng)成為比JavaScript更受開發(fā)者喜愛的編程語言了。

          之前我其實(shí)對(duì)于typescript沒有太多好感,主要是認(rèn)為其學(xué)習(xí)成本比較高,寫起代碼來還要多寫很多類型聲明,并且會(huì)受到靜態(tài)類型檢查的限制,很不自由,與javascript的設(shè)計(jì)哲學(xué)♂相悖。我相信有很多人也抱持著這樣的想法。

          然而,最近由于項(xiàng)目需要,學(xué)習(xí)并使用了一波typescript,結(jié)果。。。

          2. Typescript是什么?

          typescript,顧名思義,就是type + javascript,也就是加上了類型檢查的js。官方對(duì)于typescript的介紹也指出,typescript是javascript的超集。純粹的js語法,在typescript中是完全兼容的。但是反過來,用typescript語法編寫的代碼,卻不能在瀏覽器或者Node環(huán)境下直接運(yùn)行,因?yàn)閠ypescript本身并不是Ecmascript標(biāo)準(zhǔn)語法。

          3. 為什么要使用Typescript?

          很多人堅(jiān)持javascript而不愿使用typescript的一個(gè)很大原因是認(rèn)為javascript的動(dòng)態(tài)性高,基本不需要考慮類型,而使用typescript將會(huì)大大削弱編碼的自由度。但實(shí)際上,動(dòng)態(tài)性并不總是那么美好的。至少,現(xiàn)在javascript的動(dòng)態(tài)性帶來了以下三方面的問題:

          1. 代碼可讀性差,維護(hù)成本高。

            所謂”動(dòng)態(tài)一時(shí)爽,重構(gòu)火葬場(chǎng)“。缺乏類型聲明,對(duì)于自己非常熟悉的代碼而言,問題不大。但是如果對(duì)于新接手或者太長時(shí)間沒有接觸的代碼,理解代碼的時(shí)候需要自行腦補(bǔ)各種字段與類型,如果不幸項(xiàng)目規(guī)模比較龐大,也沒什么注釋,那么你的反應(yīng)大概會(huì)是像這樣的:

            有了typescript,每個(gè)變量類型與結(jié)構(gòu)一目了然,根本無需自行腦補(bǔ)。搭配編輯器的智能提示,體驗(yàn)可謂舒適,媽媽再也不用擔(dān)心我拼錯(cuò)字段名了。

          2. 缺乏類型檢查,低級(jí)錯(cuò)誤出現(xiàn)幾率高。

            人的專注力很難一直都保持高度在線狀態(tài),如果沒有類型檢查,很容易出現(xiàn)一些低級(jí)錯(cuò)誤。例如給某個(gè)string變量賦值數(shù)值,或給對(duì)象賦值時(shí)候缺少了某些必要字段,調(diào)用函數(shù)時(shí)漏傳或者錯(cuò)傳參數(shù)等。這些看起來很低級(jí)的錯(cuò)誤,雖然大多數(shù)情況下在自測(cè)或者測(cè)試階段,都能被驗(yàn)出來,但是總會(huì)浪費(fèi)你的一些時(shí)間去debug。

            使用typescript,這種情況甚至不會(huì)發(fā)生,一旦你粗心地賦錯(cuò)值,編輯器立即標(biāo)紅提示,將bug扼殺在搖籃之中。

          3. 類型不確定,運(yùn)行時(shí)解析器需要進(jìn)行類型推斷,存在性能問題。

            我們知道javascript是邊解析邊執(zhí)行的,由于類型不確定,所以同一句代碼可能需要被多次編譯,這就造成性能上的開銷。

            雖然typescript現(xiàn)在無法直接解決性能上的問題,因?yàn)閠ypescript最終是編譯成javascript代碼的,但是現(xiàn)在已經(jīng)有從typescript編譯到WebAssembly的工具了:https://github.com/AssemblyScript/assemblyscript。

          好了,如果看完了上面的內(nèi)容,您還是表示對(duì)于typescript不感興趣,那么后面的內(nèi)容就可以忽略了哈哈哈。。。

          4. Typescript基礎(chǔ)篇

          4.1 基礎(chǔ)類型

          typescript中的基礎(chǔ)類型有:

          其中,number、string、boolean、object、null、undefined、symbol都是比較簡單的。

          例如:

          let num: number = 1; // 聲明一個(gè)number類型的變量
          let str: string = 'string'; // 聲明一個(gè)string類型的變量
          let bool: boolean = true; // 聲明一個(gè)boolean類型的變量
          let obj: object = { // 聲明一個(gè)object類型的變量
          a: 1,
          }
          let syb: symbol = Symbol(); // 聲明一個(gè)symbol類型的變量

          null和undefined可以賦值給除了never的其他類型。

          如果給變量賦予與其聲明類型不兼容的值,就會(huì)有報(bào)錯(cuò)提示。

          例如:

          Array 數(shù)組類型

          在typescript中,有兩種聲明數(shù)組類型的方式。

          方式一:

          let arr: Array<number> = [1, 2, 3]; // 聲明一個(gè)數(shù)組類型的變量

          方式二:

          let arr: number[] = [1, 2, 3]; // 聲明一個(gè)數(shù)組類型的變量

          Tuple 元組類型

          元組類似于數(shù)組,只不過元組元素的個(gè)數(shù)和類型都是確定的。

          let tuple: [number, boolean] = [0, false];

          any類型

          當(dāng)不知道變量的類型時(shí),可以先將其設(shè)置為any類型。

          設(shè)置為any類型后,相當(dāng)于告訴typescript編譯器跳過這個(gè)變量的檢查,因此可以訪問、設(shè)置這個(gè)變量的任何屬性,或者給這個(gè)變量賦任何值,編譯器都不會(huì)報(bào)錯(cuò)。

          let foo: any;
          foo.test();
          foo = 1;
          foo = 'a';

          void類型

          通常用來聲明沒有返回值的函數(shù)的返回值類型。

          function foo(): void {
          }

          never類型

          通常用來聲明永遠(yuǎn)不會(huì)正常返回的函數(shù)的返回值類型:

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

          // 返回never的函數(shù)必須存在無法達(dá)到的終點(diǎn)
          function infiniteLoop(): never {
          while (true) {
          }
          }

          never與void的區(qū)別便是,void表明函數(shù)會(huì)正常返回,但是返回值為空。never表示的是函數(shù)永遠(yuǎn)不會(huì)正常返回,所以不可能有值。

          enum 枚舉類型

          使用枚舉類型可以為一組數(shù)值賦予友好的名字。

          enum Color {Red, Green, Blue}
          let c: Color = Color.Green;

          默認(rèn)情況下,從0開始為元素編號(hào)。你也可以手動(dòng)的指定成員的數(shù)值。例如,我們將上面的例子改成從?1開始編號(hào):

          enum Color {Red = 1, Green, Blue}
          let c: Color = Color.Green;

          或者,全部都采用手動(dòng)賦值:

          enum Color {Red = 1, Green = 2, Blue = 4}
          let c: Color = Color.Green;

          元素類型也支持字符串類型:

          enum Color {Red = 'Red', Green = 'Green', Blue = 'Blue'}
          let c: Color = Color.Green;

          枚舉類型提供的一個(gè)便利是你可以由枚舉的值得到它的名字。例如,我們知道數(shù)值為2,但是不確定它映射到Color里的哪個(gè)名字,我們可以查找相應(yīng)的名字:

          enum Color {Red = 1, Green, Blue}
          let colorName: string = Color[2];

          console.log(colorName); // 顯示'Green'因?yàn)樯厦娲a里它的值是2

          4.2 類型斷言

          有點(diǎn)類似其他強(qiáng)類型語言的強(qiáng)制類型轉(zhuǎn)換,可以將一個(gè)值斷言成某種類型,編譯器不會(huì)進(jìn)行特殊的數(shù)據(jù)檢查和結(jié)構(gòu),所以需要自己確保斷言的準(zhǔn)確性。

          斷言有兩種形式,一種為尖括號(hào)語法,一種為as語法。

          尖括號(hào)語法:

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

          as語法:

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

          在大部分情況下,這兩種語法都可以使用,但是在jsx中就只能使用as語法了。

          5. Typescript進(jìn)階篇

          5.1 函數(shù)

          函數(shù)類型:

          函數(shù)類型主要聲明的是參數(shù)和返回值的類型。

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

          約等于

          const sum: (numberA: number, numberB: number) => number = function(a: number, b: number): number {
          return a + b;
          }

          注意到類型定義時(shí)參數(shù)的名稱不一定要與實(shí)際函數(shù)的名稱一致,只要類型兼容即可。

          可選參數(shù):

          函數(shù)參數(shù)默認(rèn)都是必填的,我們也可以使用可選參數(shù)。

          function sum(a: number, b: number, c?: number): number {
          return c ? a + b + c : a + b;
          }

          重載:

          javascript本身是個(gè)動(dòng)態(tài)語言。javascript里函數(shù)根據(jù)傳入不同的參數(shù)而返回不同類型的數(shù)據(jù)是很常見的。

          來看個(gè)簡單但沒什么用的例子:

          function doNothing(input: number): number;
          function doNothing(input: string): string;
          function doNothing(input): any {
          return input;
          }

          console.log(doNothing(123));
          console.log(doNothing('123'));

          當(dāng)然也可以使用聯(lián)合類型,但是編譯器就無法準(zhǔn)確知道返回值的具體類型。

          function doNothing(input: number | string): number | string {
          return input;
          }
          console.log(doNothing('123').length); // 錯(cuò)誤:Property 'length' does not exist on type 'string | number'

          如果只是單純參數(shù)的個(gè)數(shù)不同,返回值類型一樣,建議使用可選參數(shù)而不是重載。

          function sum(a: number, b: number, c?: number) {
          return c ? a + b + c : a + b;
          }

          5.2 interface 接口

          對(duì)于一些復(fù)雜的對(duì)象,需要通過接口來定義其類型。

          interface SquareConfig {
          color: string;
          width: number;
          }

          const square: SquareConfig = {
          color: 'red', width: 0,
          };

          可選屬性:

          默認(rèn)情況下,每個(gè)屬性都是不能為空的。如果這么寫,將會(huì)有報(bào)錯(cuò)。

          interface SquareConfig {
          color: string;
          width: number;
          }
          const square: SquareConfig = {
          color: 'red',
          };// error

          可以將用"?"將width標(biāo)志位可選的屬性:

          interface SquareConfig {
          color: string;
          width?: number;
          }
          const square: SquareConfig = {
          color: 'red',
          };

          只讀屬性

          一些對(duì)象屬性只能在對(duì)象剛剛創(chuàng)建的時(shí)候修改其值。你可以在屬性名前用?readonly來指定只讀屬性。

          interface Point {
          readonly x: number;
          readonly y: number;
          }

          如果在初始化后試圖修改只讀屬性的值,將會(huì)報(bào)錯(cuò)。

          let p: Point = { x: 10, y: 20 };
          p.x = 20; // error

          函數(shù)類型

          接口除了能夠描述對(duì)象的結(jié)構(gòu)之外,還能描述函數(shù)的類型。

          interface SumFunc {
          (a: number, b: number): number;
          }

          let sum: SumFunc;

          sum = (numberA: number, numberB: number) => {
          return numberA + numberB;
          }

          可以看到函數(shù)的類型與函數(shù)定義時(shí)只要參數(shù)類型一致即可,參數(shù)名不一定要一樣。

          可索引類型

          可索引類型,實(shí)際就是聲明對(duì)象的索引的類型,與對(duì)應(yīng)值的類型。接口支持兩種索引類型,一種是number,一種是string,通過可索引類型可以聲明一個(gè)數(shù)組類型。

          interface StringArray {
          [index: number]: string;
          }

          let myArray: StringArray;
          myArray = ["Bob", "Fred"];

          let myStr: string = myArray[0];

          5.3 class 類

          typescript中的類是javascript中類的超集,所以如果你了解es6中的class的語法,也不難理解typescript中class的語法了。

          這里主要說下typescript的class和javascript的class的不同之處:

          • 只讀屬性

          • public、private、protected修飾符

          • 抽象類

          • 實(shí)現(xiàn)接口

          只讀屬性

          類似于接口中的只讀屬性,只能在類實(shí)例初始化的時(shí)候賦值。

          class User {
          readonly name: string;
          constructor (theName: string) {
          this.name = theName;
          }
          }

          let user = new User('Handsome');
          user.name = 'Handsomechan'; // 錯(cuò)誤!name是只讀的

          public、private、protected修飾符:

          public修飾符表示屬性是公開的,可以通過實(shí)例去訪問該屬性。類屬性默認(rèn)都是public屬性。

          class Animal {
          constructor(public name: string) {}
          }
          const animal = new Animal('tom');
          console.log(animal.name); // 'tom'

          注意在類的構(gòu)造函數(shù)參數(shù)前加上修飾符是一個(gè)語法糖,上面的寫法等價(jià)于:

          class Animal {
          public name: string;
          constructor(name: string) {
          this.name = name;
          }
          }

          private修飾符表示屬性是私有的,只有實(shí)例的方法才能訪問該屬性。

          class Animal {
          getName(): string { return this.name }
          constructor(private name: string) {}
          }
          const animal = new Animal('tom');
          console.log(animal.getName()); // 'tom'
          console.log(animal.name); // Property 'name' is private and only accessible within class 'Animal'.

          protected修飾符表示屬性是保護(hù)屬性,只有實(shí)例的方法和派生類中的實(shí)例方法才能訪問到。

          class Animal {
          constructor(public name: string, protected age: number) {}
          }

          class Cat extends Animal {
          getAge = ():number => {
          return this.age;
          }
          }

          const cat = new Cat('tom', 1);
          console.log(cat.getAge()); // 1

          抽象類

          抽象類做為其它派生類的基類使用。它們一般不會(huì)直接被實(shí)例化。不同于接口,抽象類可以包含成員的實(shí)現(xiàn)細(xì)節(jié)。?abstract關(guān)鍵字是用于定義抽象類和在抽象類內(nèi)部定義抽象方法。

          abstract class Animal {
          abstract makeSound(): void; // 抽象方法,必須在派生類中實(shí)現(xiàn)
          move(): void {
          console.log('roaming the earch...');
          }
          }
          class Sheep extends Animal {
          makeSound() {
          console.log('mie~');
          }
          }
          const animal = new Animal(); // 錯(cuò)誤,抽象類不能直接實(shí)例化
          const sheep = new Sheep();
          sheep.makeSound();
          sheep.move();

          實(shí)現(xiàn)接口

          類可以實(shí)現(xiàn)一個(gè)接口,從而使得類滿足這個(gè)接口的約束條件。

          interface ClockInterface {
          currentTime: Date;
          }

          class Clock implements ClockInterface {
          currentTime: Date;
          constructor(h: number, m: number) { }
          }

          5.4 泛型

          泛型在強(qiáng)類型語言中很常見,泛型支持在編寫代碼時(shí)候使用類型參數(shù),而不必在一開始確定某種特定的類型。這樣做的原因有兩個(gè):

          1. 有時(shí)候沒辦法在代碼被使用之前知道類型。

            例如我們封裝了一個(gè)request函數(shù),用來發(fā)起http請(qǐng)求,返回請(qǐng)求響應(yīng)字段。

            我們?cè)趯?shí)現(xiàn)request函數(shù)的時(shí)候,實(shí)際上是不能知道響應(yīng)字段有哪些內(nèi)容的,因?yàn)檫@跟特定的請(qǐng)求相關(guān)。

            所以我們將類型確定的任務(wù)留給了調(diào)用者。

            // 簡單封裝了一個(gè)request函數(shù)
            async function request<T>(url: string): Promise<T> {
            try {
            const result = await fetch(url).then((response) => {
            return response.json();
            });
            return result;
            } catch (e) {
            console.log('request fail:', e);
            throw e;
            }
            }

            async function getUserInfo(userId: string): void {
            const userInfo = await request<{
            nickName: string;
            age: number;
            }>(`user_info?id=${userId}`)
            console.log(userInfo); // { nickName: 'xx', age: xx }
            }

            getUserInfo('123');
          1. 提高代碼的復(fù)用率。

            如果對(duì)于不同類型,代碼的操作都是一樣的,那么可以使用泛型來提高代碼的復(fù)用率。

            // 獲取數(shù)組或者字符串的長度
            function getLen<T extends Array<any> | string>(arg: T): number {
            return arg ? arg.length : 0;
            }

          當(dāng)然,您可能覺得這兩點(diǎn)在javascript中都可以輕易做到,根本不需要泛型。是的,泛型本身是搭配強(qiáng)類型食用更佳的,在弱類型下沒意義。

          在typescript中,泛型有幾種打開方式:

          泛型函數(shù):

          function someFunction<T>(arg: T) : T {
          return arg;
          }
          console.log(someFunction<number>(123)); // 123

          泛型類型:

          • interface

            interface UserInfo {
            id: T;
            age: number;
            }
            const userInfo: UserInfo<number> = {
            id: 123,
            age: 23,
            }
          • type

            type UserInfo = { // 同上
            id: T;
            age: number;
            }
            const userInfo: UserInfo<string> = {
            id: '123',
            age: 123,
            }

          泛型類:

          class UserInfo {
          constructor(private id: T, private age: number) {};
          getId(): T {
          return this.id;
          }
          }

          我們也可以給類型變量加上一些約束。

          泛型約束

          有時(shí)編譯器不能確定泛型里面有什么屬性,就會(huì)出現(xiàn)報(bào)錯(cuò)的情況。

          function logLength<T>(arg: T): T {
          console.log(arg.length); // Error: T doesn't have .length
          return arg;
          }

          解決方法是加上泛型約束。

          interface TypeWithLength {
          length: number,
          }
          function logLength<T extends TypeWithLength>(arg: T): T {
          console.log(arg.length); // ok
          return arg;
          }

          6. Typescript高級(jí)篇

          6.1 高級(jí)類型

          交叉類型

          交叉類型是將多個(gè)類型合并為一個(gè)類型。

          interface typeA {
          a?: number,
          }

          interface typeB {
          b?: number,
          }

          let value: typeA & typeB = {};

          value.a = 1; // ok
          value.b = 2; // ok

          聯(lián)合類型

          聯(lián)合類型表示變量屬于聯(lián)合類型中的某種類型,使用時(shí)需要先斷言一下。

          interface TypeA {
          a?: number,
          }

          interface TypeB {
          b?: number,
          }

          const value: TypeA | TypeB = {};

          (value).a = 1; // ok

          6.2 類型別名 type

          類型別名可以給一個(gè)類型起個(gè)新名字。類型別名有時(shí)和接口很像,但是可以作用于原始值,聯(lián)合類型,元組以及其它任何你需要手寫的類型。可以將type看做存儲(chǔ)類型的特殊類型。

          type Name = string;
          type NameResolver = () => string;
          type NameOrResolver = Name | NameResolver;
          ...

          6.3 is

          is關(guān)鍵字通常組成類型謂詞,作為函數(shù)的返回值。謂詞為?parameterName is Type這種形式,?parameterName必須是來自于當(dāng)前函數(shù)簽名里的一個(gè)參數(shù)名。

          function isFish(pet: Fish | Bird): pet is Fish {
          return (pet).swim !== undefined;
          }

          這樣的好處是當(dāng)函數(shù)調(diào)用后,如果返回true,編譯器會(huì)將變量的類型鎖定為那個(gè)具體的類型。

          例如:

          if (isFish(pet)) {
          pet.swim(); // 進(jìn)入這里,編譯器認(rèn)為petFish類型。
          } else {
          pet.fly(); // 進(jìn)入這里,編譯器認(rèn)為petBird類型。
          }

          6.4 keyof

          keyof索引類型查詢操作符

          interface Person {
          name: string;
          age: number;
          }
          type IndexType = keyof Person; // 'name' | 'age'

          這樣做的好處是使得編譯器能夠檢查到動(dòng)態(tài)屬性的類型。

          function pick<T, K extends keyof T>(obj: T, keys: K[]): T[K][] {
          return keys.map(key => obj[key]);
          }

          console.log(pick(person, ['name', 'age'])); // [string, number]

          6.5 聲明合并

          為什么需要聲明合并呢?

          我們思考一下,在javascript中,一個(gè)對(duì)象是不是可能有多重身份。

          例如說,一個(gè)函數(shù),它可以作為一個(gè)普通函數(shù)執(zhí)行,它也可以是一個(gè)構(gòu)造函數(shù)。同時(shí),函數(shù)本身也是對(duì)象,它也可以有自己的屬性。

          所以這注定了typescript中的類型聲明可能存在的復(fù)雜性,需要進(jìn)行聲明的合并。

          合并接口

          最簡單也最常見的聲明合并類型是接口合并。從根本上說,合并的機(jī)制是把雙方的成員放到一個(gè)同名的接口里。

          interface Box {
          height: number;
          width: number;
          }

          interface Box {
          scale: number;
          }

          let box: Box = {height: 5, width: 6, scale: 10};

          接口的非函數(shù)的成員應(yīng)該是唯一的。如果它們不是唯一的,那么它們必須是相同的類型。如果兩個(gè)接口中同時(shí)聲明了同名的非函數(shù)成員且它們的類型不同,則編譯器會(huì)報(bào)錯(cuò)。

          對(duì)于函數(shù)成員,每個(gè)同名函數(shù)聲明都會(huì)被當(dāng)成這個(gè)函數(shù)的一個(gè)重載。同時(shí)需要注意,當(dāng)接口?A與后來的接口?A合并時(shí),后面的接口具有更高的優(yōu)先級(jí)。

          合并命名空間

          Animals聲明合并示例:

          namespace Animals {
          export class Zebra { }
          }

          namespace Animals {
          export interface Legged { numberOfLegs: number; }
          export class Dog { }
          }

          等同于:

          namespace Animals {
          export interface Legged { numberOfLegs: number; }

          export class Zebra { }
          export class Dog { }
          }

          命名空間與類和函數(shù)和枚舉類型合并

          類與命名空間的合并:

          class Album {
          label: Album.AlbumLabel;
          }
          namespace Album {
          export class AlbumLabel { }
          }

          函數(shù)與命名空間的合并:

          function buildLabel(name: string): string {
          return buildLabel.prefix + name + buildLabel.suffix;
          }

          namespace buildLabel {
          export let suffix = "";
          export let prefix = "Hello, ";
          }

          console.log(buildLabel("Sam Smith"));

          此外,類與枚舉、命名空間與枚舉等合并也是可以的,這里不再話下。

          6.6 聲明文件

          聲明文件通常是以.d.ts結(jié)尾的文件。

          如果只有ts、tsx文件,那么其實(shí)不需要聲明文件。聲明文件一般是在用第三方庫的時(shí)候才會(huì)用到,因?yàn)榈谌綆於际莏s文件,加上聲明文件之后,ts的編譯器才能知道第三庫暴露的方法、屬性的類型。

          聲明語法:

          • declare vardeclare letdeclare const聲明全局變量

            // src/jQuery.d.ts
            declare let jQuery: (selector: string) => any;
          • declare function?聲明全局方法

            declare function jQuery(selector: string): any;
          • declare class聲明全局類

            // src/Animal.d.ts
            declare class Animal {
            name: string;
            constructor(name: string);
            sayHi(): string;
            }
          • declare enum?聲明全局枚舉類型

            declare enum Directions {
            Up,
            Down,
            Left,
            Right
            }
          • declare namespace?聲明(含有子屬性的)全局變量

            // src/jQuery.d.ts

            declare namespace jQuery {
            function ajax(url: string, settings?: any): void;
            }
          • interfacetype聲明全局類型

            interface AjaxSettingsInterface {
            method?: 'GET' | 'POST'
            data?: any;
            }

            type AjaxSettingsType = {
            method?: 'GET' | 'POST'
            data?: any;
            }
          • export?導(dǎo)出變量

            在聲明文件中只要用到了export、import就會(huì)被視為模塊聲明文件。模塊聲明文件中的declare關(guān)鍵字不能聲明全局變量

            // types/foo/index.d.ts

            export const name: string;
            export function getName(): string;
            export class Animal {
            constructor(name: string);
            sayHi(): string;
            }
            export enum Directions {
            Up,
            Down,
            Left,
            Right
            }
            export interface Options {
            data: any;
            }

            對(duì)應(yīng)的導(dǎo)入和使用模塊應(yīng)該是這樣:

            // src/index.ts

            import { name, getName, Animal, Directions, Options } from 'foo';

            console.log(name);
            let myName = getName();
            let cat = new Animal('Tom');
            let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
            let options: Options = {
            data: {
            name: 'foo'
            }
            };
          • export namespace導(dǎo)出(含有子屬性的)對(duì)象

            // types/foo/index.d.ts

            export namespace foo {
            const name: string;
            namespace bar {
            function baz(): string;
            }
            }

            // src/index.ts

            import { foo } from 'foo';

            console.log(foo.name);
            foo.bar.baz();

          • export default?ES6 默認(rèn)導(dǎo)出

            // types/foo/index.d.ts

            export default function foo(): string;
            // src/index.ts

            import foo from 'foo';

            foo();
          • export =?commonjs 導(dǎo)出模塊

            // 整體導(dǎo)出
            module.exports = foo;
            // 單個(gè)導(dǎo)出
            exports.bar = bar;

            在 ts 中,針對(duì)這種模塊導(dǎo)出,有多種方式可以導(dǎo)入,第一種方式是?const ... = require

            // 整體導(dǎo)入
            const foo = require('foo');
            // 單個(gè)導(dǎo)入
            const bar = require('foo').bar;

            第二種方式是import ... from,注意針對(duì)整體導(dǎo)出,需要使用?import * as來導(dǎo)入:

            // 整體導(dǎo)入
            import * as foo from 'foo';
            // 單個(gè)導(dǎo)入
            import { bar } from 'foo';

            第三種方式是?import ... require,這也是 ts 官方推薦的方式:

            // 整體導(dǎo)入
            import foo = require('foo');
            // 單個(gè)導(dǎo)入
            import bar = foo.bar;
          • export as namespace?庫聲明全局變量

            既可以通過?

            <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>
                    亚洲色图欧洲 | 五月激情丁香 | 青娱乐精品在线观看视频 | 成人片无码免费 | 操逼黄色片 |