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
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...