<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      TypeScript(十二)模塊

      目錄

      引言

      d.ts聲明文件

      declare關鍵字

      全局聲明

      全局聲明方式

      全局聲明一般用作

      函數聲明

      在.ts中使用declare

      外部模塊(文件模塊)

      模塊關鍵字module

      聲明模塊

      模塊聲明方式

      模塊通配符

      模塊導出

      模塊嵌套

      模塊的作用域

      模塊別名

      內部模塊(命名空間)

      命名空間 OR 模塊?

      global關鍵字

      總結

      參考文章


      引言

      本文收錄于TypeScript知識總結系列文章,歡迎指正! 

      將體量大的程序拆分成多個小的,功能獨立的模塊是開發中不可或缺的一環,開發復雜程序的核心之一就是讓其變得不復雜。模塊化開發可以提高代碼的可維護性、可重用性、可擴展性和可測試性,從而提高了開發效率和代碼質量,TypeScript沿用了JS的模塊概念,在之前文章中我介紹過Node環境下的兩種類型兼容,順帶提了一下目前常用的模塊導入導出方式:Commonjs和ES Module,這兩種方式在TS中被稱為是外部模塊,除此之外TS還包含了內部模塊和全局模塊,本文將逐一介紹

      d.ts聲明文件

      在編譯后的JS文件的同一級常能看到.d.ts后綴的聲明文件,其作用是描述代碼中已經存在的類型信息或為其提供類型聲明。舉個例子,使用第三方庫時可能會找不到對應的類型信息,于是TS提供了聲明文件這個概念,它使開發者擁有對庫進行描述的能力,達到靜態類型提示或者TS檢查的目的,聲明文件編譯后不會生成任何js代碼。

      一般聲明文件內部是不包含可執行語句的,只有類型或者變量的聲明。在開發時通常會在項目根目錄中新建一個像global.d.ts(名字自取)的文件用于描述全局的類型,變量,函數,類等等

      declare關鍵字

      declare是描述TS文件之外信息的一種機制,它的作用是告訴TS某個類型或變量已經存在,我們可以使用它聲明全局變量、函數、類、接口、類型別名、類的屬性或方法以及后面會介紹的模塊與命名空間

      全局聲明

      通常在global.d.ts文件中使用declare關鍵字進行全局聲明,以便目錄下所有文件都能直接訪問

      全局聲明方式

      • declare var 名稱: 變量
      • declare const / let 名稱: ES6變量
      • declare function 名稱: 方法
      • declare class 名稱: 類
      • declare enum 名稱: 枚舉
      • declare module 名稱: 模塊
      • declare namespace 名稱: 命名空間
      • declare interface 名稱: 接口
      • declare type 名稱: 類型別名

      全局聲明一般用作

      • 描述全局變量或類型
      • 描述第三方庫的類型
      • 描述全局模塊

      舉個例子,在項目根目錄新建global.d.ts用于變量類型的全局聲明,接著修改tsconfig中配置include為["global.d.ts", "src"],在項目任意目錄新建index.ts

      // global.d.ts
      declare interface IAnimal {
          name: string
          age?: number
      }
      
      declare let animal: IAnimal
      // src/index.ts
      animal = {
          name: "阿黃"
      }

      可以看到index.ts文件中animal的類型是global.d.ts中聲明的變量,其二者產生了關聯

       

      tips:聲明文件(d.ts)中的所有類型(類型別名和接口除外)及變量都要使用declare定義,或者使用export將其導出,否則會拋出以下錯誤:.d.ts 文件中的頂級聲明必須以 "declare" 或 "export" 修飾符開頭。

      此外,使用類型別名和接口定義的類型可以不需要聲明,直接在全局訪問

      declare type str = string
      // 相當于type str = string

      函數聲明

      參照上面的定義方式,我們可以在聲明文件中聲明一個函數,然后再使用前對函數進行實現或重載

      // global.d.ts
      declare function add(a: number, b: number): number;
      
      // src/index.ts
      function add(a: number, b: number) {
          return a + b
      }
      console.log(add(1, 2));// 3
      
      // src/main.ts
      function add(a: number, b: number, c: string) {
          return a + b + c
      }
      console.log(add(1, 2, "3"));// 33

      對函數聲明進行重載

      在.ts中使用declare

      我們在介紹屬性裝飾器的時候曾用到了declare關鍵字,當時并沒有具體說明使用它的原因,這里咱們詳細分析一下,首先貼出一段類似的代碼

      class Animal {
          name?: string;
      }

      在ES2022及以后類中定義的屬性會在編譯后保留在類中,就像

      class Animal {
          name;
      }

      而在.ts文件中使用declare只會被當成是類型或者變量的定義,最后編譯在聲明文件.d.ts中,不會編譯在.js文件中,就像下面這個類

      // index.ts
      declare class Animal {
          name?: string;
      }
      
      // index.js
      // 空文件
      
      // index.d.ts
      declare class Animal {
          name?: string;
      }

      通過declare這個特點,我們可以在類中屬性或者方法定義時使用declare關鍵字將其指定為聲明類型的變量,不會出現在.js中,有效的解決之前的問題

      // index.ts
      class Animal {
         declare name?: string;
      }
      
      // index.js
      class Animal {}

      外部模塊(文件模塊)

      在TS中模塊既可以以單個文件的形式存在,這與JS相同,通過export和import兩個關鍵字進行導出導入,對應的介紹可以參照這篇文章的ESM部分,也可以使用module關鍵字定義模塊。

      與JS稍有不同,TS中包含了接口和類型別名,我們同樣可以通過export type 類型名 導出對應類型別名,如

      // src/main.ts
      export type IAnimal = {
          name: string
          color?: string
      }
      
      // src/index.ts
      import { IAnimal } from './main'
      const animal: IAnimal = {
          name: "阿黃",
      };

      tips:在一個.d.ts文件中使用export關鍵字會使這個文件成為一個模塊(這點很重要,一個聲明文件(d.ts)不是全局聲明文件(只使用declare聲明類型)就得是文件模塊(使用export等關鍵字導出)),比如我們把上面的global文件和index改成下面代碼

      // global.d.ts
      type IAnimal = {
          name: string
          color?: string
      }
      export {}
      
      // index.ts
      const animal: IAnimal = {
          name: "阿黃",
      };

      此時直接使用全局的IAnimal就會拋錯

      必須使用export將IAnimal導出并使用import導入該模塊中的類型

      模塊關鍵字module

      聲明模塊

      除了上面的使用方式外,我們可以使用module關鍵字在一個文件中定義多個模塊,如

      // global.d.ts
      declare module 'global_type' {
          export type IAnimal = {
              name: string
          }
          export type ICat = {
              name: string
          }
      }
      declare module 'global_type1' {
          export type IDog = {
              name: string
          }
      }
      
      // index.ts
      import type { IAnimal, ICat } from "global_type"
      import type { IDog } from 'global_type1'
      const animal: IAnimal = {
          name: "阿黃",
      };
      const dog: IDog = animal
      const cat: ICat = animal

      每一個使用module定義的內容是一個模塊

      模塊聲明方式

      TS支持CommonJS和ESM兩種模塊系統,使得聲明模塊有兩種寫法,分別是使用字符串和變量名

      CommonJS的寫法遵循匹配文件的相對或絕對路徑,通常模塊名作為字符串字面量,該方法不支持導出模塊,只允許使用declare定義全局模塊,并且使用時需要使用import導入

      // global.d.ts 
      declare module "global_type" {
          export type IAnimal = {
              name: string
          }
      }
      
      // src/index.ts
      import * as global_type from "global_type"
      const myObject: global_type.IAnimal = {}

      ESM的寫法和定義變量一樣,使用變量名匹配標識符進行模塊的導入,這種方式與定義命名空間(namespace)的效果一樣,使用ESM定義的全局模塊可以直接使用,不需要導入

      // global.d.ts 
      declare module global_type {
          export type IAnimal = {
              name?: string
          }
      }
      
      // src/index.ts
      const myObject: global_type.IAnimal = {}

      模塊通配符

      我們在webpack或者vite等工具中可能會看到類似下面的代碼,這種寫法是CommonJS模塊系統獨有的

      declare module '*.type' {
          export type IDog = {
              name: string
          }
      }

      這段代碼中使用了*.type通配符,匹配了所有.type結尾的模塊,導入.type類型的文件就會有IDog這個類型

      import type { IDog } from 'global_type.type'
      const animal: IDog = {
          name: "阿黃",
      };
      const dog: IDog = animal

      模塊導出

      使用module定義的模塊遵循全局聲明,同樣可以使用export導出并在其他文件使用,這種方式是ESM模塊系統獨有的

      // global.d.ts 
      export module global_type {
          export type IAnimal = {
              name: string
          }
          export class Animal implements IAnimal {
              name: string
          }
      }
      
      // index.ts
      import { global_type } from '../global'
      const myObject: global_type.IAnimal = new global_type.Animal();

      模塊嵌套

      模塊嵌套可以應對更復雜的結構,避免命名沖突,全局污染,在模塊中寫模塊不需要declare和export關鍵字,模塊默認自帶導出

      // global.d.ts 
      declare module global_type {
          export module IAnimalModule {
              export let animal: IAnimal
              export type IAnimal = {
                  name: string
              }
          }
          module IDogModule {
              let dog: IDog
              type IDog = {
                  name?: string
              }
          }
      }
      // src/index.ts
      let animal: global_type.IAnimalModule.IAnimal = global_type.IAnimalModule.animal
      let dog: global_type.IDogModule.IDog = global_type.IDogModule.dog

      模塊的作用域

      在模塊嵌套時,我們可以把 module { } 或者 namespace { } 的大括號中的作用域稱為模塊的作用域,作用域中的模塊類型可以訪問,此時如果在模塊中使用 export {} 導出空對象的話,當前模塊就會被視為文件模塊(這和我們上面說到的全局文件轉模塊文件的tips類似),需要使用export導出局部類型、變量、模塊,否則會默認不做導出操作,成為一個私有的模塊:

      // global.d.ts 
      declare module global_type {
          module IAnimalModule { // 局部模塊,只能在global_type中使用
              let animal: IAnimal
              type IAnimal = {
                  name?: string
              }
          }
          export { }
      }
      
      // src/index.ts
      let animal: global_type.IAnimalModule.IAnimal// “global_type”沒有已導出的成員“IAnimalModule”

      此時需要將模塊中的模塊手動導出,或加入到導出對象中

      export module IAnimalModule {
          let animal: IAnimal
          type IAnimal = {
              name?: string
          }
      }
      // 或者
      export { IAnimalModule }

      模塊別名

      模塊的別名是一種用來簡化其訪問的方式,可以使用import關鍵字來定義一個別名,然后用這個別名來代替原來的名稱,比如

      // global.d.ts 
      declare module global_type {
          export type IAnimal = {
              name?: string
          }
          export class Animal implements IAnimal { }
      }
      
      // src/index.ts
      import Ani = global_type.Animal
      import IAni = global_type.IAnimal
      const ami: IAni = new Ani()

      內部模塊(命名空間)

      因為1.5版本前的命名空間(namespace)是TS提出的模塊理念,而上面說到的模塊是JS中的ES標準,TypeScript對二者做了區分,所以它被稱為內部模塊。它同樣是模塊化機制的一員,它的作用是將全局的變量,函數,類等等封裝在一個空間內,防止命名污染,沖突。官方比較推薦使用namespace來代替module的ESM模塊系統寫法,所以在使用模塊的變量寫法時,TS會將其轉換成namespace

       

      還記得上面說的ESM模塊系統的導出方式嗎?我們把代碼中的module關鍵字換成namespace,就大功告成了,命名空間擁有模塊的變量寫法的特性。

      namespace global_type {
          export type IAnimal = {
              name: string
          }
          export class Animal implements IAnimal {
              name: string
          }
      }
      const myObject: global_type.IAnimal = new global_type.Animal();

      我們把代碼放到一個文件中解析一下編譯后的JS文件

      var global_type;
      (function (global_type) {
          class Animal {
              name;
          }
          global_type.Animal = Animal;
      })(global_type || (global_type = {}));
      const myObject = new global_type.Animal();

      可以看到,代碼中使用iife產生了一個私有的作用域并且定義了一個空對象,將命名空間導出的變量放至對象中。

      思考一個問題,一個命名空間必須通過一處代碼塊定義嗎?

      答案是否定的,類似函數重載,命名空間的定義允許聲明合并,將同名的命名空間對象進行合并(后面的文章會說到,留個懸念)

      命名空間 OR 模塊?

      模塊適用于需要動態加載、封裝和復用代碼的場景,比如Node.js應用、Web應用、npm包等。模塊可以利用模塊加載器(如CommonJS/Require.js)或支持ES模塊的運行時來管理依賴和導入導出。模塊是ES6標準的一部分,是現代代碼的推薦組織方式。

      命名空間適用于需要在全局范圍內定義變量、函數、類、接口等的場景,比如Web應用中使用<script>標簽引入所有依賴的HTML頁面。命名空間可以避免全局變量的命名沖突,但也會增加組件依賴的難度,尤其是在大型應用中。

      global關鍵字

      在TS中declare global關鍵字用于向全局作用域中添加類型或變量的聲明

      以我的理解,global的使用方式應該和module以及namespace類似,照葫蘆畫瓢,使用global { ... }作為一個代碼塊表示全局的作用域,在里面定義的類型以及變量應該是能夠在任意地方取到的

      // global.d.ts 
      declare global {
          type IDog = {
              name: string
          }
          let animal: IDog
      }
      
      // src/index.ts
      animal = {
          name: "阿黃"
      }

      然而事情并沒有這么簡單,它會提示:全局范圍的擴大僅可直接嵌套在外部模塊中或環境模塊聲明中。

      在官方給出的d.ts模板中,代碼最后一行做了一個導出的操作

      這是為何?

      實際上這是為了解決TS編譯器的一個問題,上面我們說到,如果聲明文件d.ts沒有使用export導出或者沒有使用declare定義類型、變量,那么編譯器就會報錯,而使用declare global和使用declare module、declare namespace、declare type、declare interface都不一樣,這些類型或者模塊的定義就是導出聲明,不需要進行額外的export。所以在定義(說是拓展比較貼切)全局的global時會在代碼底部導出空對象,來聲明這個文件是有導出的

      上面我們提到:使用export關鍵字會使聲明文件成為一個模塊;如果使用了declare global和export { },那么我們的全局變量和類型就不需要使用declare聲明,可以直接寫在declare global代碼塊中

      下面是一個完整的示例

      // global.d.ts 
      declare global {
          type IDog = {
              name: string
          }
          let animal: IDog
      }
      export { }
      
      // src/index.ts
      animal = {
          name: "阿黃"
      }

      總結

      文章寫到這里也就結束了,本文簡述了TS中模塊的使用,針對聲明文件,declare關鍵字,文件模塊,命名空間以及全局global關鍵字這幾個方面進行了介紹,同時提出了自己的看法及遇到的問題,希望能對你有幫助。

      感謝你看到最后,如果覺得文章還不錯的話,還請點贊收藏關注支持一下博主,對文章內容有任何問題還望在評論區留言或私信,感謝!

      參考文章

      命名空間和模塊 - TypeScript 中文手冊

      TypeScript: Documentation - Global .d.ts

      TypeScript: Documentation - Modules

      typescript已經有模塊系統了,為什么還需要namespace? - 知乎

      posted @ 2023-04-18 16:54  阿宇的編程之旅  閱讀(300)  評論(0)    收藏  舉報  來源
      主站蜘蛛池模板: 国产 麻豆 日韩 欧美 久久| 亚洲精品漫画一二三区| 久久夜色精品国产亚av| 亚洲欧洲一区二区精品| 亚洲成在人天堂一区二区| 人人妻人人做人人爽夜欢视频| 国产69精品久久久久久| 国产乱人伦av在线无码| 亚洲自在精品网久久一区| 新巴尔虎左旗| 国产线播放免费人成视频播放| 國產尤物AV尤物在線觀看| 欧美国产日产一区二区| 中文无码精品a∨在线| 久久亚洲精品日本波多野结衣| 国产乱码精品一区二三区| 九九re线精品视频在线观看视频| 中文字幕有码日韩精品| 久久免费观看归女高潮特黄 | 依依成人精品视频在线观看| 亚洲午夜无码av毛片久久| 国产精品无码专区av在线播放| 亚洲另类激情专区小说图片| 耿马| 中文字幕无码成人免费视频| 最新中文字幕国产精品| 欧美福利电影A在线播放| 精品国产品香蕉在线| 亚洲精品无码av天堂| 蜜臀av久久国产午夜福利软件| 韩国午夜福利片在线观看| 免费ā片在线观看| 亚洲精品一区二区三区蜜| 亚洲av日韩在线资源| 99精品热在线在线观看视| 一本高清码二区三区不卡| 国产午夜福利精品久久不卡| 男女激情一区二区三区| 日韩一区精品视频一区二区| 免费无码一区无码东京热| 国产mv在线天堂mv免费观看|