
本文介绍在 .d.ts 文件中避免重复声明、高效复用接口成员定义类实例形状的正确方式:通过同名接口合并与 interface extends 实现类型继承。
本文介绍在 `.d.ts` 文件中避免重复声明、高效复用接口成员定义类实例形状的正确方式:通过同名接口合并与 interface extends 实现类型继承。
在 TypeScript 声明文件(.d.ts)中,为 JavaScript 类编写类型定义时,常遇到一类典型场景:类在运行时通过 Object.assign(this, options) 将构造参数的全部属性直接挂载到实例上(如 new C({ foo: 42, bar: "hello" }) 后,实例即具备 foo 和 bar 属性)。此时,若手动在 class C 中逐个重复声明这些属性,不仅冗余易错,更违背 DRY(Don’t Repeat Yourself)原则。
✅ 正确且推荐的做法是:利用 TypeScript 的声明合并(Declaration Merging)机制,为类定义一个同名的空接口,并让该接口继承目标选项接口。例如:
// mylib.d.ts
interface Options {
foo: number;
bar: string;
}
// 声明一个同名接口 C,继承 Options —— 这将自动为类实例添加 foo 和 bar 类型
interface C extends Options {}
// 类声明仅需关注签名,无需重复属性
declare class C {
constructor(options: Options);
}
这样,TypeScript 编译器会将 interface C 与 class C 合并,使 C 的实例类型同时包含 Options 的所有成员(即 c.foo 和 c.bar 被正确识别为 number 和 string),而无需在 class 主体中显式写出字段。
⚠️ 注意事项:
-
interface C extends Options {}必须与class C处于同一作用域(如同一文件或全局声明空间),且名称严格一致; - 不要尝试使用
class C implements Options—— 因为Options是普通接口(非可实现契约),且implements仅约束类的公共方法/属性声明,不参与实例类型推导; - 若类本身还拥有其他自有属性(如
id: string或方法log()),可在interface C中补充声明:interface C extends Options { id: string; log(): void; }
总结:借助接口继承 + 声明合并,既保持了 .d.ts 文件的简洁性与可维护性,又精准表达了 JavaScript 动态赋值行为下的静态类型契约——这是为“属性注入型”类编写高质量类型声明的核心模式。











