TS从入门到放弃【十七】:声明合并

1,359 阅读3分钟

声明合并:指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}

小结:如果在使用接口或命名空间的时候,在其中指定了字段之后,使用的时候可能发现在其中没有指定过的字段提示你缺少了。

此时可能就是你在别的地方定义了同名的接口或命名空间,导致他们进行了合并造成的。