声明合并:指TS编译器会将名字相同的多个声明合并为一个声明。合并后的声明同时拥有多个声明的特性。
在 TS 中,接口和命名空间是可以多次声明的(声明同样名字的接口或命名空间)。
1、同名接口的合并
interface InfoInter {
name: string;
}
interface InfoInter {
age: number;
}
上面我们定义了两个同名的接口,接下来我们来定义一个变量,指定变量的类型是 InfoInter 这个接口
let infoInter: InfoInter = { // Error
name: 'dylan',
};
此时可以看到是报错状态的,因为我们的参数中缺少 age 属性,具体报错内容如下:
类型 "{ name: string; }" 中缺少属性 "age",但类型 "InfoInter" 中需要该属性。
所以我们需要补上 age 属性:
let infoInter: InfoInter = {
name: 'dylan',
age: 18
};
TS 中所有的声明概括起来,会创建三种实体之一:命名空间、类型、值
命名空间的创建,实际上是创建一个对象,对象的属性是你再命名空间中
export导出的内容。类型的声明,是创建一个类型,并且赋给一个名字。
值的声明,是在 TS 中创建一个可以使用的值。
- Namespace:命名空间
- Class:类型、值
- Enum:类型、值
- Interface:类型
- Type Alias类型别名:类型
- Function:值
- Variable:值
- 多个同名接口定义的非函数成员,命名应该是不重复的。如果重复了,类型应该是相同的,否则就会报错。
interface InfoInter {
name: string;
}
interface InfoInter {
name: number; // Error:后续属性声明必须属于同一类型。属性“name”的类型必须为“string”,但此处却为类型“number”。
}
从上述代码中可以看出,同名接口中的非函数成员命名如果重复的话,类型需要是相同的。
- 对于函数成员,每个同名函数成员都会被当作是函数的重载,且合并的时候,后面的接口具有更高的优先级
interface InfoInter {
name: string;
getRes(input: string): number;
}
interface InfoInter {
age: number;
getRes(input: number): string;
}
let infoInter: InfoInter = {
name: 'dylan',
age: 18,
getRes(text: any): any {
if(typeof text === 'string') { return text.length; }
else { return String(text); }
}
};
2、同名命名空间的合并
同名的命名空间会将多个命名空间导出的内容进行合并。
namespace Validations {
export const checkNumber = () => {};
}
namespace Validations {
export const checkLetter = () => {};
}
定义上述的两个命名空间,等同于下面的代码:
namespace Validations {
export const checkNumber = () => {};
export const checkLetter = () => {};
}
如果我们在其中一个命名空间里,有些内容没有使用 export 修饰,那么在另一个命名空间中是无法获取到的:
namespace Validations {
const numberReg = /^[0-9]+$/;
export const checkNumber = () => {};
}
namespace Validations {
console.log(numberReg); // Error:找不到名称“numberReg”。
export const checkLetter = () => {};
}
3、同名命名空间和类合并
要求:类一定要在前面。
合并之后的结果是一个包含以命名空间导出内容为静态属性的类。
class Validations {
constructor() {}
public checkType() {}
}
namespace Validations {
export const numberReg = /^[0-9]+$/;
}
console.dir(Validations); // class方法,里面静态属性有一个 numberReg
4、同名命名空间和函数合并
要求:函数一定要在前面。
在 JS 中,函数也是对象,所以可以给一个函数设置属性。
function countUp() {
countUp.count++;
}
namespace countUp {
export let count = 0;
}
console.log(countUp.count); // 0
countUp();
console.log(countUp.count); // 1
5、同名命名空间合枚举合并
可以通过命名空间和枚举的合并,为枚举拓展内容。
枚举和命名空间的先后顺序是没有要求的。
enum Colors {
red,
green,
blue
}
namespace Colors {
export const yellow = 3;
}
// 注意:没有 3: 'yellow'
console.log(Colors); // {0: 'red', 1: 'green', 2: 'blue', red: 0, green: 1, blue: 2, yellow: 3}
小结:如果在使用接口或命名空间的时候,在其中指定了字段之后,使用的时候可能发现在其中没有指定过的字段提示你缺少了。
此时可能就是你在别的地方定义了同名的接口或命名空间,导致他们进行了合并造成的。