当前位置: 首页 > news >正文

【阮一峰】14.命名空间

命名空间

简介

namespace 是一种将相关代码组织在一起的方式。出现在 ES 模块诞生之前,作为 TypeScript 自己的模块格式而发明的。但是,自从有了 ES 模块,官方已经不推荐使用 namespace 了。

基本用法

namespace 用来建立一个容器,内部的所有变量和函数,都必须在这个容器里面使用。

namespace Utils {
  function isString(value: any) {
    return typeof value === "string";
  }

  // 正确
  isString("yes");
}

Utils.isString("no"); // 报错

如果要在命名空间以外使用内部成员,就必须为该成员加上 export 前缀,表示对外输出该成员。

namespace Utility {
  export function log(msg: string) {
    console.log(msg);
  }
  export function error(msg: string) {
    console.error(msg);
  }
}

Utility.log("Call me");
Utility.error("maybe!");

namespace 编译后会变成一个值,保留在编译后的代码中。它不是纯的类型代码。

namespace 内部还可以使用 import 命令输入外部成员,相当于为外部成员起别名。当外部成员的名字比较长时,别名能够简化代码。

namespace Utils {
  export function isString(value: any) {
    return typeof value === "string";
  }
}

namespace App {
  import isString = Utils.isString;

  isString("yes");
  // 等同于
  Utils.isString("yes");
}

import 命令也可以在 namespace 外部,指定别名。

namespace Shapes {
  export namespace Polygons {
    export class Triangle {}
    export class Square {}
  }
}

import polygons = Shapes.Polygons;

// 等同于 new Shapes.Polygons.Square()
let sq = new polygons.Square();

namespace 可以嵌套。

namespace Utils {
  export namespace Messaging {
    export function log(msg: string) {
      console.log(msg);
    }
  }
}

// 使用嵌套的命名空间,必须从最外层开始引用
Utils.Messaging.log("hello"); // "hello"

namespace 不仅可以包含实义代码,还可以包括类型代码。

namespace N {
  export interface MyInterface {}
  export class MyClass {}
}

namespace 与模块的作用是一致的,都是把相关代码组织在一起,对外输出接口。

区别是一个文件只能有一个模块,但可以有多个 namespace。

:::tip
由于模块可以取代 namespace,而且是 JavaScript 的标准语法,还不需要编译转换,所以建议总是使用模块,替代 namespace。
:::

如果 namespace 代码放在一个单独的文件里,那么引入这个文件需要使用三斜杠的语法。

/// <reference path = "SomeFileName.ts" />

namespace 的输出

namespace 本身也可以使用 export 命令输出,供其他文件使用。

// shapes.ts
export namespace Shapes {
  export class Triangle {
    // ...
  }
  export class Square {
    // ...
  }
}

其他脚本文件使用 import 命令,加载这个命名空间。

// 写法一
import { Shapes } from "./shapes";
let t = new Shapes.Triangle();

// 写法二
import * as shapes from "./shapes";
let t = new shapes.Shapes.Triangle();

不过还是建议使用模块,采用模块的输出和输入。

namespace 的合并

多个同名的 namespace 会自动合并,这一点跟 interface 一样。

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

// 等同于
namespace Animals {
  export class Cat {}
  export interface Legged {
    numberOfLegs: number;
  }
  export class Dog {}
}

合并命名空间时,命名空间中的非 export 的成员不会被合并,且它们只能在各自的命名空间中使用。

namespace N {
  const a = 0;

  export function foo() {
    console.log(a); // 正确
  }
}

namespace N {
  export function bar() {
    foo(); // 正确
    console.log(a); // 报错
  }
}

命名空间还可以跟同名函数合并,但是要求同名函数必须在命名空间之前声明。

:::tip
这样做是为了确保先创建出一个函数对象,然后同名的命名空间就相当于给这个函数对象添加额外的属性。
:::

function f() {
  return f.version;
}

namespace f {
  export const version = "1.0";
}

f(); // '1.0'
f.version; // '1.0'

命名空间也能与同名 class 合并,同样要求 class 必须在命名空间之前声明,原因同上。

class C {
  foo = 1;
}

namespace C {
  export const bar = 2;
}

C.bar; // 2

命名空间还能与同名 Enum 合并。

enum E {
  A,
  B,
  C,
}

namespace E {
  export function foo() {
    console.log(E.C);
  }
}

E.foo(); // 2

:::warning
Enum 成员与命名空间导出成员不允许同名。
:::

enum E {
  A, // 报错
  B,
}

namespace E {
  export function A() {} // 报错
}

相关文章:

  • 学习总结2.18
  • ppt中如何快速自动地将整页标题和大段文字自动设计形状和颜色
  • kafka消费能力压测:使用官方工具
  • 大模型工具大比拼:SGLang、Ollama、VLLM、LLaMA.cpp 如何选择?
  • 刚性平衡机建模
  • [Android] Battery Guru - 手机电量管理优化
  • stm32rtc实时时钟详解文章
  • 学习查看 linux 关于进程的文件信息 cat /proc/968/status
  • LNMP+Zabbix安装部署(Zabbix6.0 Lnmp+Zabbix Installation and Deployment)
  • 02.05、链表求和
  • 【算法】回溯算法
  • spring boot知识点3
  • Dart 3.5 学习汇总(更新中)
  • 【Pandas】pandas Series last
  • Docker镜像拉取失败解决方案
  • centos7配置rsyslog日志服务器
  • 【阮一峰】5.函数
  • C++:并发编程基础
  • 【前端ES】ECMAScript 2023 (ES14) 引入了多个新特性,简单介绍几个不为人知但却好用的方法
  • 华为交换机堆叠技术简介配置
  • 上海发布首份直播电商行业自律公约,禁止虚假宣传、商业诋毁
  • 2025世界数字教育大会将于5月14日至16日在武汉举办
  • 纽约大学朗格尼医学中心的转型带来哪些启示?
  • 夜读丨古代有没有近视眼?
  • 九家企业与上海静安集中签约,投资额超10亿元
  • 夜读丨母亲的手擀面