一,前言
本篇介绍TS中的重复命名的声明合并
1,声明合并定义
2,接口的声明合并及对接口成员的要求
3,命名空间的声明合并
4,命名空间和函数的声明合并
5,命名空间和类的声明合并
6,命名空间和枚举的声明合并
二,声明合并
声明合并:
编译器会将程序中多个具有相同名称的声明合并为一个声明
优势:
可以将程序中散落在各处的重名声明合并在一起
三,接口的声明合并
接口的声明合并是TS中最常见的一种声明合并
比如,在多个文件中定义同名接口,使用时,会对多个定义同时感知
通过合并避免对接口成员的遗漏
定义两个同名接口,具有不同属性:
interface A {
x: number
}
interface A {
y: number
}
这时,两个接口就会合并称成一个接口:
定义变量a为A接口类型,a需要具备两个接口中的所有成员
let a: A = {
x: 1,
y: 2
}
在全局模块中,两个接口不在一个文件中也可以发生接口合并
接口的成员-非函数成员:
接口中非函数的成员,需要保证接口成员的唯一性,如果不唯一类型必须相同
在A中重复定义成员y,但类型相同,不报错:
interface A {
x: number
y: number // 在A中重复定义成员y,但类型相同
}
interface A {
y: number
}
let a: A = {
x: 1,
y: 2
}
在A中重复定义成员y,但类型不同,报错:
interface A {
x: number
y: string // 在A中重复定义成员y,但类型不同
}
interface A {
y: number
}
let a: A = {
x: 1,
y: 2
}
接口的成员-函数成员:
每一个函数都会被声明为一个函数重载
在A接口中定义函数:
interface A {
x: number
foo(bar: number):number
}
interface A {
y: number
foo(bar: string):string
foo(bar: number[]):number[]
}
在接口中定义的foo函数,实现了函数重载
实现时,需要指定更为宽泛的类型
let a: A = {
x: 1,
y: 2,
foo(bar: any) {
return bar
}
}
函数重载时,我们提到要注意重载函数的声明顺序,
因为函数重载会使用从重载列表中匹配到第一个
接口合并时顺序是如何确定的?
1,接口之内,从上到下
// 1,接口之间,从上到下
interface A {
y: number
foo(bar: string):string // 1
foo(bar: number[]):number[] // 2
}
2,接口之间,后面的接口在前
// 2,接口之间,后面的接口在前
interface A {
x: number
foo(bar: number):number // 3
}
interface A {
y: number
foo(bar: string):string // 1
foo(bar: number[]):number[] // 2
}
3,例外,如果函数的参数是字符串字面量,会被提升到函数声明的最顶端
// 3,例外,如果函数的参数是字符串字面量,会被提升到函数声明的最顶端
interface A {
x: number
foo(bar: number):number // 5
foo(bar: 'a'):number // 2
}
interface A {
y: number
foo(bar: string):string // 3
foo(bar: number[]):number[] // 4
foo(bar: 'b'):number // 1
}
三,命名空间的声明合并
命名空间的声明合并在上一篇已经涉及到了
注意:
在命名空间中,导出的成员是不能重复定义的
namespace2.ts
// 命名空间
namespace Shape {
export function square(x: number){
return x * x
}
}
namespace.ts
namespace Shape {
const pi = Math.PI
// 全局可见
export function cricle(r: number){
return pi * r ** 2
}
export function square(x: number){ // 重复定义,会报错
return x * x
}
}
四,命名空间和函数的声明合并
定义一个函数和同名的命名空间
// 命名空间和函数的声明合并
function Lib() {}
namespace Lib {
export let version = '1.0'
}
console.log(Lib.version) // 1.0
这就相当于先声明一个函数,再添加属性
五,命名空间和类的声明合并
声明一个类和同名的命名空间
// 命名空间和类的声明合并
class C {}
namespace C {
export let state = 1
}
console.log(C.state) // 1
这就相当于给类添加静态属性
六,命名空间和枚举的声明合并
定义一个枚举和同名的命名空间:
// 命名空间和枚举的声明合并
enum Color {
Red,
Yellow,
Bule
}
namespace Color {
export function mix() {}
}
相当于为枚举类型添加了方法
需要注意:
命名空间在与函数,类进行声明合并时,一定要放在函数,类的定义后面
枚举和命名空间的位置没有要求
七,结尾
在程序中,有多出同名声明其实并不好,最好能封装在模块内
TS照顾了旧工程,如果引入TS,仍能够与老代码共存