跳至内容
张叶安的小站
用户工具
登录
站点工具
搜索
工具
显示页面
过去修订
反向链接
最近更改
媒体管理器
网站地图
登录
>
最近更改
媒体管理器
网站地图
您的足迹:
typescript:第九章声明合并
本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。
====== 第九章 声明合并 ====== 声明合并(Declaration Merging)是TypeScript的一个独特特性,它允许编译器将多个同名的声明合并为一个单一的声明。这种机制使得可以分多次定义同一个实体,特别适用于扩展第三方库类型定义或组织大型代码库。 ===== 9.1 基本概念 ===== 在TypeScript中,"声明"会创建实体,包括命名空间、类型或值三种之一。声明合并就是将具有相同名称的多个独立声明合并为一个定义。 <code typescript> // 接口合并 interface Box { height: number; width: number; } interface Box { scale: number; } // 合并后的Box接口 let box: Box = { height: 5, width: 6, scale: 10 }; </code> ===== 9.2 可合并的声明类型 ===== ==== 9.2.1 接口合并 ==== 接口是合并最常见和最有用的场景。多个同名接口会自动合并。 <code typescript> // 接口合并规则: // 1. 非函数成员必须唯一,否则报错 // 2. 同名函数成员会重载 interface Document { createElement(tagName: "div"): HTMLDivElement; createElement(tagName: "span"): HTMLSpanElement; } interface Document { createElement(tagName: string): HTMLElement; createElement(tagName: any): Element; } // 合并后的Document接口包含所有createElement重载 </code> 合并规则详解: - **非函数成员**:必须是唯一的类型,如果出现重复且类型不兼容会报错 - **函数成员**:每个同名函数声明都会被当作重载处理 - **重载顺序**:后面的接口声明会排在前面,但具体实现签名始终在最后 <code typescript> interface Animal { name: string; move(): void; } interface Animal { age: number; move(): string; // 重载 } // 合并结果: // interface Animal { // name: string; // age: number; // move(): string; // 重载1 // move(): void; // 重载2 // } </code> ==== 9.2.2 命名空间合并 ==== 命名空间可以相互合并,也可以与类、函数或枚举合并。 <code typescript> // 命名空间之间的合并 namespace Animals { export class Zebra {} } namespace Animals { export interface Legged { numberOfLegs: number; } export class Dog {} } // 合并后的Animals命名空间包含Zebra、Dog和Legged </code> 命名空间合并规则: - 导出的成员必须唯一 - 非导出成员只在原始命名空间中可见 <code typescript> namespace Animal { let haveMuscles = true; export function animalsHaveMuscles() { return haveMuscles; } } namespace Animal { export function doAnimalsHaveMuscles() { return haveMuscles; // Error: haveMuscles在此不可见 } } </code> ==== 9.2.3 命名空间与类合并 ==== 命名空间可以与类合并,用于创建内部类或相关类型。 <code typescript> class Album { label: Album.AlbumLabel; } namespace Album { export class AlbumLabel { constructor(public name: string) {} } } // 使用 let album = new Album(); album.label = new Album.AlbumLabel("Interscope"); </code> 这种模式的用途: - 将辅助类/类型与主类组织在一起 - 实现静态属性的类型安全 <code typescript> // 静态属性的类型安全 class Handler { static version: Handler.Version; } namespace Handler { export enum Version { V1 = "1.0", V2 = "2.0" } } Handler.version = Handler.Version.V1; </code> ==== 9.2.4 命名空间与函数合并 ==== 函数可以与命名空间合并,用于添加属性或创建可调用的命名空间。 <code typescript> function buildLabel(name: string): string { return buildLabel.prefix + name + buildLabel.suffix; } namespace buildLabel { export let suffix = ""; export let prefix = "Hello, "; } console.log(buildLabel("Sam")); // "Hello, Sam" buildLabel.suffix = "!"; console.log(buildLabel("Sam")); // "Hello, Sam!" </code> 这种模式常用于: - 创建带配置的函数 - 类似jQuery的可调用对象 <code typescript> // 类似jQuery的函数+命名空间模式 declare function $(selector: string): NodeListOf<Element>; declare function $<T extends Element>(element: T): T; declare namespace $ { export function ajax(url: string, settings?: any): Promise<any>; export const version: string; export fn: { extend(object: any): void; }; } // 使用 $(".item"); $.ajax("/api/data"); </code> ==== 9.2.5 命名空间与枚举合并 ==== 命名空间可以与枚举合并,用于添加静态方法。 <code typescript> enum Color { red = 1, green = 2, blue = 4 } namespace Color { export function mixColor(colorName: string) { if (colorName == "yellow") { return Color.red + Color.green; } if (colorName == "white") { return Color.red + Color.green + Color.blue; } } } console.log(Color.mixColor("yellow")); // 3 </code> ==== 9.2.6 类合并限制 ==== 类不能直接与其他类或变量合并。 <code typescript> class A {} class A {} // Error: 重复的标识符 const B = class {}; class B {} // Error: 重复的标识符 </code> 但可以通过接口来扩展类的类型定义: <code typescript> class A { x: number = 1; } interface A { y: number; } const a = new A(); a.y = 2; // OK </code> ===== 9.3 扩展第三方库 ===== 声明合并最常见的用途是扩展第三方库的类型定义。 ==== 9.3.1 扩展全局对象 ==== <code typescript> // 扩展Window对象 declare global { interface Window { myLib: { version: string; doSomething(): void; }; } } // 使用 window.myLib.doSomething(); </code> ==== 9.3.2 扩展模块 ==== <code typescript> // 扩展express的Request对象 import { Request } from "express"; declare module "express" { interface Request { user?: { id: string; name: string; }; requestTime: number; } } // 在express中间件中使用 app.use((req, res, next) => { req.requestTime = Date.now(); next(); }); </code> ==== 9.3.3 扩展现有类 ==== <code typescript> // 扩展Array原型(类型层面) declare global { interface Array<T> { last(): T | undefined; first(): T | undefined; } } // 运行时实现 if (!Array.prototype.last) { Array.prototype.last = function() { return this[this.length - 1]; }; } // 使用 const arr = [1, 2, 3]; console.log(arr.last()); // 3 </code> ===== 9.4 模块增强模式 ===== ==== 9.4.1 声明文件中的合并 ==== 在.d.ts文件中,声明合并对于库作者特别有用。 <code typescript> // mylib.d.ts // 主声明 export interface Config { apiUrl: string; timeout: number; } export function initialize(config: Config): void; // 扩展声明 export namespace Config { export interface AdvancedOptions { retries: number; cache: boolean; } } </code> ==== 9.4.2 拆分大型接口 ==== <code typescript> // user.types.ts export interface User { id: string; name: string; } // user-profile.types.ts import { User } from "./user.types"; declare module "./user.types" { interface User { profile: { avatar: string; bio: string; }; } } // 使用 const user: User = { id: "1", name: "John", profile: { avatar: "avatar.jpg", bio: "Hello" } }; </code> ===== 9.5 全局模块扩展 ===== 使用declare global可以在模块中向全局作用域添加声明。 <code typescript> // utils.ts export {}; declare global { interface String { capitalize(): string; } function assert(condition: any, msg?: string): asserts condition; } // 实现 String.prototype.capitalize = function() { return this.charAt(0).toUpperCase() + this.slice(1); }; // 使用 import "./utils"; console.log("hello".capitalize()); // "Hello" </code> ===== 9.6 实际应用案例 ===== ==== 9.6.1 插件系统类型定义 ==== <code typescript> // 核心应用类型 export interface Application { name: string; plugins: Plugin[]; use(plugin: Plugin): void; } export interface Plugin { name: string; install(app: Application): void; } // 扩展点声明 export namespace Application { export interface ComponentRegistry { [name: string]: any; } } // 插件可以扩展Application // plugin.d.ts declare module "./app" { interface Application { components: Application.ComponentRegistry; registerComponent(name: string, component: any): void; } } </code> ==== 9.6.2 状态管理库扩展 ==== <code typescript> // store.ts export interface State { count: number; } export interface Store { state: State; commit(mutation: string, payload?: any): void; } // mutations.ts export const mutations = { increment(state: State) { state.count++; } }; // 扩展Store以支持类型安全的commit declare module "./store" { interface Store { commit(type: "increment"): void; commit(type: "add", payload: number): void; } } </code> ==== 9.6.3 API客户端类型扩展 ==== <code typescript> // api-client.ts export interface ApiClient { get<T>(url: string): Promise<T>; post<T>(url: string, data: any): Promise<T>; } export class ApiClientImpl implements ApiClient { async get<T>(url: string): Promise<T> { // 实现 return {} as T; } async post<T>(url: string, data: any): Promise<T> { // 实现 return {} as T; } } // 特定API模块扩展客户端 declare module "./api-client" { interface ApiClient { getUser(id: string): Promise<User>; createUser(data: CreateUserData): Promise<User>; } } // 实现扩展 ApiClientImpl.prototype.getUser = function(id: string) { return this.get(`/users/${id}`); }; </code> ===== 9.7 注意事项 ===== ==== 9.7.1 合并顺序 ==== 接口成员的顺序遵循声明的顺序,函数重载有特殊规则。 <code typescript> interface Example { foo(x: number): void; // 1 } interface Example { foo(x: string): void; // 2 } interface Example { foo(x: any): void; // 3 (实现签名) } // 实际重载顺序: 2, 1, 3 </code> ==== 9.7.2 类型兼容性 ==== 合并的成员类型必须兼容。 <code typescript> interface A { x: number; } interface A { x: string; // Error: 类型不兼容 } </code> ==== 9.7.3 可见性规则 ==== 命名空间合并时,非导出成员保持私有。 <code typescript> namespace Outer { let privateVar = 1; export function getPrivate() { return privateVar; } } namespace Outer { export function tryAccess() { // 可以访问privateVar,因为这是同一个命名空间 return privateVar; } } </code> ===== 9.8 小结 ===== 声明合并是TypeScript类型系统的一个强大特性,它允许: 1. **接口合并**:创建完整的类型定义 2. **命名空间合并**:组织和拆分代码 3. **命名空间与类/函数/枚举合并**:创建静态成员和可调用对象 4. **模块扩展**:安全地扩展第三方库类型 5. **全局扩展**:向全局对象添加类型定义 合理使用声明合并可以提高代码的可维护性和可扩展性,特别是在大型项目和库开发中。但需要注意合并规则,避免类型冲突。
typescript/第九章声明合并.txt
· 最后更改:
2026/02/03 22:31
由
127.0.0.1
页面工具
显示页面
过去修订
反向链接
回到顶部