声明合并机制
TypeScript的声明合并机制允许将多个同名的声明自动合并为一个,这在类型定义和代码组织上提供了极大的灵活性。理解这一机制有助于更好地利用TypeScript的类型系统,尤其是在扩展第三方库或模块时。
声明合并的基本概念
声明合并指的是编译器将多个同名的声明合并为单个定义的过程。这种机制适用于接口、命名空间、类和枚举等类型声明。例如:
interface Box {
height: number;
}
interface Box {
width: number;
}
const box: Box = {
height: 100,
width: 200,
};
这里两个Box
接口被合并为一个,同时包含height
和width
属性。如果同名属性类型冲突,编译器会报错。
接口的声明合并
接口是最常见的声明合并场景。合并时,非函数成员的同名属性必须类型一致,否则会报错;函数成员则会重载:
interface Cloner {
clone(animal: Animal): Animal;
}
interface Cloner {
clone(animal: Sheep): Sheep;
}
// 合并结果为:
interface Cloner {
clone(animal: Animal): Animal;
clone(animal: Sheep): Sheep;
}
函数重载的顺序取决于声明顺序,后声明的优先级更高。但若使用字面量类型或泛型,规则会更复杂。
命名空间的合并
命名空间可以与同名命名空间、类、函数或枚举合并。与命名空间合并时,导出的成员会合并:
namespace Animals {
export class Zebra {}
}
namespace Animals {
export interface Legged {
numberOfLegs: number;
}
export class Dog {}
}
// 合并结果为:
namespace Animals {
export interface Legged {
numberOfLegs: number;
}
export class Zebra {}
export class Dog {}
}
命名空间与类合并时,静态成员会被扩展:
class Album {
label: Album.AlbumLabel;
}
namespace Album {
export class AlbumLabel {}
}
类与枚举的合并
类只能与命名空间合并,不能与其他类合并。枚举的合并行为与接口类似:
enum Color {
Red = 1,
}
enum Color {
Green = 2,
Blue = 4,
}
// 合并结果为:
enum Color {
Red = 1,
Green = 2,
Blue = 4,
}
模块扩展的场景
声明合并常用于扩展第三方模块的类型定义。例如扩展vue-router
:
import { Route } from 'vue-router';
declare module 'vue-router' {
interface RouteMeta {
requiresAuth?: boolean;
icon?: string;
}
}
这种方式不会修改原始代码,但能获得完整的类型支持。
合并的优先级与限制
合并的优先级规则:
- 后声明的接口成员优先级更高
- 命名空间合并时,后导出的成员会覆盖前者
- 类与命名空间合并时,命名空间必须位于类之后
限制包括:
- 变量和函数不能合并(除非使用命名空间)
- 泛型类型参数必须完全一致才能合并
复杂示例:React组件属性扩展
通过声明合并扩展React组件props:
import * as React from 'react';
declare module 'react' {
interface HTMLAttributes<T> {
customAttr?: string;
}
}
function Component() {
return <div customAttr="value" />;
}
这种模式在组件库开发中极为常见,尤其是需要扩展原生HTML属性时。
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn