声明合并是 TypeScript 的独特特性,允许将多个同名的声明合并为一个实体。这与 TypeScript 作为 JavaScript 上的类型化的历史有关:许多第三方库声明了接口、函数、命名空间,而 TypeScript 必须允许在不修改库的源代码的情况下扩展它们。
在复杂的 API 中以及对第三方 JS 库进行类型化时,可能需要分配责任——例如,扩展模块的类型、添加接口字段、合并名称。然而,大多数语言不支持这样的声明合并。
TypeScript 允许合并同名的接口、命名空间、函数、类的声明,这使得 API 在扩展时更具灵活性。它用于扩展第三方类型、向库添加自定义方法,以及组织模块化代码。
代码示例:
// 接口合并 interface User { id: number; } interface User { name: string; } const u: User = { id: 1, name: "Jack" }; // 命名空间 + 函数合并 function greet() { return "Hi!"; } namespace greet { export function loud() { return "HI!"; } } greet(); // "Hi!" greet.loud(); // "HI!"
关键特性:
可以将 type alias 像接口那样合并吗?
不可以,type alias 不能合并。尝试声明多个具有相同名称的 type 会导致编译错误。
type T = { a: string }; type T = { b: number }; // 错误
TypeScript 会以随机顺序插入接口/命名空间字段吗?
合并的结构总是按声明顺序构建——如果存在相同属性名称,则最后的声明“获胜”。
接口的方法会合并为一个函数吗?
不会,具有相同名称的方法在不同接口中不会合并为一个函数——如果签名匹配,TypeScript 仍然不允许实现“两个”变体。
公司两次定义全局接口 Window,其字段不同且同名字段的类型也不同。在构建过程中,构建工具没有发现问题,但在运行时会出现意外的类型冲突。
优点:
缺点:
为第三方库编写 d.ts 文件,API 接口在不改变库本身的情况下由单独模块扩展,所有扩展都有文档说明,命名策略在 Wiki 中描述。
优点:
缺点: