TS 導入導出那些事

来源:https://www.cnblogs.com/QiFande/archive/2023/04/07/ts-about-export.html
-Advertisement-
Play Games

最近用 TypeScript 寫 npm 包,各種模塊、命名空間、全局定義等等擾得我睡不著覺。我苦心研究,總結了幾個比較冷門的,國內貌似基本上找不到資料的導入導出用法,順便在其中又插入一些不那麼冷門的用法,於是本篇文章來了。 ...


前言

最近用 TypeScript 寫 npm 包,各種模塊、命名空間、全局定義等等擾得我睡不著覺。

我便苦心研究,總結了幾個比較冷門的,國內貌似基本上找不到資料的導入導出用法,順便在其中又插入一些不那麼冷門的用法,於是本篇文章來了。

因為一開始也沒想做成大全,可能之後還會繼續更新吧。

目錄

導入模塊

導入模塊中的東西相信大家都不陌生。唯一需要註意的便是預設導出與“星號”導出的區別。

import * as Mod from './mod';
// 類似於
const Mod = require('./mod');
import ModDef from './mod';
// 類似於
const { default: ModDef } = require('./mod');
import ModDef, { a, b } from './mod';

// 類似於
const {
	default: ModDef,
	a, b
} = require('./mod');

在模塊中導出

在模塊中導出東西相信大家也不陌生,不過這裡還是詳細講解一下。

在模塊中導出東西有很多種方法。導出總共可分為 4 類:

命名導出

命名導出有兩種方法,一種是聲明著導出

export namespace A { }
export function b() { }
export class C { }
export const d = 123;
export let { e } = { e: 'hh' };

一種是聲明後導出

namespace A { }
function b() { }
class C { }
const d = 123;
let { e } = { e: 'hh' };

export { A, b, C, d, e };

聲明後導出比聲明著導出更靈活,能合併,也能重命名

namespace A { }
export { A };

function b() { }
export { b as c };

class C { }
export { C as B };

const d = 123;
let { e } = { e: 'hh' };
export { d, e };

命名導出編譯成 Common JS 後類似這樣

exports.xxx = xxx;

需要註意的是其他人無法修改任何你導出的東西。即使是使用 let 聲明也一樣

/* mod.ts */
export let a = 123;

/* others.ts */
import { a } from './mod';
a = 321; // 報錯:ts(2632)

不過對於上面的代碼,你可以隨便修改所導出的 a 。因為其他人每次讀取 a 時都會重新從你的導出對象上訪問一次 a 屬性,不用擔心其他人無法接收到你的修改。具體可以查看編譯後的 JS 文件

/* others.ts */
import { a } from './mod';
const b = a + 123;
console.log(a);

/* others.js */
var mod_1 = require("./mod");
var b = mod_1.a + 123;
console.log(mod_1.a);

預設導出

預設導出可以理解為一種特殊的命名導出。

預設導出的名字是 default 。但是你不能搞個名字叫 default 的變數然後導出,你必須得用 export default 或者在導出時重命名

export let default = 123; // 報錯:ts(1389)

export default 123; // 正確

export let a = 123;
export { a as default }; // 正確

星號導入搭配預設導出,可以達到預設導出即為星號導出的效果

/* mod.ts */
import * as Self from './mod';
export default Self;

/* others.ts */
import * as Mod from './mod';
import ModDef from './mod';
console.log(Mod === ModDef); // true

星號導出

星號導出可以導出其他模塊里的東西。一般有兩種用法。

第一種是全導出到自己裡頭,就像

export * from './xxx'

具體效果是 xxx 中導出的東西,也可以通過你訪問到。

/* xxx.ts */
export let a = { hh: 'hh' };

/* mod.ts */
export * from './xxx.ts';

/* others.ts */
import { a } from './xxx';
import { a } from './mod';
console.log(a === a); // true

第二種是掛到自己模塊下麵,就像

export * as xxx from './xxx';
// 等價於
import * as xxx from './xxx';
export { xxx };

導出分配

導出分配就是把 Common JS 的導出搬到了 TS 中。寫法也差不多

export = 'hh';
// 相當於
module.export = 'hh';

導出分配也可以指定預設導出,只需要有 default 屬性就可以

/* mod.ts */
export = { default: 123 };

/* others.ts */
import mod from './mod';
console.log(mod); // 123

需要註意的是採用了導出分配後便不能再使用其他導出方法。

導入命名空間

雖然現在命名空間相較於模塊並不是特別常用,但它還是有比較完整的導入導出功能的。

導入命名空間中的東西很簡單,像這樣

import xxx = Space.xxx;

不論你是在模塊中導入全局命名空間,還是在命名空間中導入其他命名空間,都是適用的。

import Err = globalThis.Error;
throw Err('hh');

namespace A {
	import Process = NodeJS.Process;
	let proce: Process;
}

較為可惜的是命名空間貌似沒有星號導入,也不支持解構導入。

在命名空間中導出

在一般 TS 中,命名空間只有兩種方法導出。

第一種方法是聲明著導出,類似於模塊

namespace A {
	export const a = 123;
}

第二種方法是導入著導出,可以用來導出其他命名空間的東西

namespace A {
	export import Err = globalThis.Error;
}

而對於不一般的 TS ——也就是類型聲明中,命名空間還可以採用像模塊一樣的導出對象

declare namespace A {
	const a = 123;
	const b = 'hh';
	export { a, b };
}

使用全局定義

全局定義一般有三種:

  1. 內置在 TS 中的全局定義。比如 setTimeoutError 等。
    對於這種全局定義,直接拿來用就可以了。

  2. 位於環境模塊中的全局定義。比如 NodeJS.Process 等。

    包括位於 node_modules/@types 文件夾中的自動引入的環境模塊,都可以通過三斜杠註釋來引入。

    你可以通過 path 直接指定文件路徑

    /// <reference path="./types.d.ts" />
    
  3. 位於模塊中的全局定義。

    這種全局定義只需要引入一下模塊,表示你已經運行此模塊,即可

    import '@babel/core';
    

    或者你也可以通過三斜杠註釋,通過 types 指定模塊

    /// <reference types="@babel/core" />
    

    需要註意的是,不論你採用 import 還是三斜杠註釋,甚至只是在類型中使用了一個 typeof import('xxx') ,只要你在一個 TS 文件中引入了這個模塊所定義的全局類型,那這個類型就會永遠存在下去,污染你的 globalThis
    唯一在不污染全局域的情況下運行模塊的方法是使用 import() 函數動態引入,但這樣子你也拿不到你需要的類型。

進行全局定義

進行全局定義一般有三種方法。

第一種是直接寫環境模塊。不帶任何 importexport 一般就會讓編譯器把這當成一個環境模塊。所以,如果你需要防止一個 TS 文件變成環境模塊導致類型泄露的話,你可以加一個安全無公害的 export { };

第二種是在模塊中定義,只需要把類型定義寫到 declare global 裡頭就行

declare global {
	const a = 123;
	let b: {};
}

a; // 123
b; // {}

第三種是通過合併 globalThis 命名空間來定義,好處是可以使用命名空間的“導入著導出”方法,將模塊或者其他命名空間的局部變數變成全局變數

import _Mod from './mod';

declare global {
	namespace globalThis {
		const a = 123;
		export import Mod = _Mod;
	}
}

a; // 123
Mod; // typeof import('./mod')

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、MySQLl和Navicat的關係 Mysql一個關係型資料庫管理系統,由瑞典MysqlLAB公司開發,目前屬於Oracle旗下產品,是目前最流行的關心型資料庫管理系統之一。 Navicat一個資料庫管理工具,用可視化界面提供給用戶操作Mysql資料庫管理系統。 記得我第一次安裝Navicat之 ...
  • 我們知道 Flink 有Table(表)、View(視圖)、Function(函數/運算元)、Database(資料庫)的概念,相對於這些耳熟能詳的概念,Flink 里還有一個 Catalog(目錄) 的概念。 本文將為大家帶來 Flink Catalog 的介紹以及 Flink Catalog 在 ...
  • Hadoop簡介安裝 狹義上Hadoop指的是Apache軟體基金會的一款開源軟體用java語言實現,開源允許用戶使用簡單的編程模型實現跨機器集群對海量數據進行分散式計算處理 Hadoop核心組件 Hadoop HDFS(分散式文件存儲系統):解決海量數據存儲 Hadoop YARN(集群資源管理和 ...
  • 摘要:本文主要通過實例講解如何通過gs_cpuwatcher.sh 腳本尋找CPU占用高語句。 本文分享自華為雲社區《GaussDB(DWS) gs_cpuwatcher.sh 腳本如何尋找CPU占用高語句》,作者:fighttingman。 【工具名稱】 gs_cpuwatcher 【功能描述】 ...
  • 為什麼要分庫分表 用戶請求量太大 單伺服器TPS、記憶體、IO都是有上限的,需要將請求打散分佈到多個伺服器 。 單庫數據量太大 單個資料庫處理能力有限;單庫所在伺服器的磁碟空間有限;單庫上的操作IO有瓶頸 。 單表數據量太大 查詢、插入、更新操作都會變慢,在加欄位、加索引、機器遷移都會產生高負載,影響 ...
  • Mysql 01 使用CMD連接資料庫 -- 在控制台連接資料庫(需將位置切換到mysql所在地址) mysql -u root -p password:12345 -- 修改mysql賬戶密碼及許可權,安裝配置完後慎用 update mysql.user set authentication_str ...
  • 前言 不同微信版本,關閉廣告的方式不一樣,今天嘗試關閉微信版本 8.0.33 廣告,但是發現最後還是關不掉,故寫下此文,希望對大家死了關閉廣告這條心! 操作如下 步驟一:點擊設置—>關於微信 步驟二:點擊進入《隱私保護指引》 步驟三:在第一大類中找到 1.34 小類,其中有個藍色字樣《個性化廣告》, ...
  • Flutter 是由 Google 創建的免費開源的移動應用程式開發框架。可以用它為 iOS、Android 和 Web 平臺,開發界面華麗、高性能、響應式的應用程式。Flutter 基於 Dart 編程語言,並使用 Skia 圖形庫來渲染其組件。 和很多其它框架一樣,Flutter 宣稱其主要特性 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...