交叉类型(Intersection Types)

交叉类型是将多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。 例如, Person & Serializable & Loggable同时是 Person Serializable Loggable。 就是说这个类型的对象同时拥有了这三种类型的成员。
我们大多是在混入(mixins)或其它不适合典型面向对象模型的地方看到交叉类型的使用。 (在JavaScript里发生这种情况的场合很多!) 下面是如何创建混入的一个简单例子:

  1. function extend<T, U>(first: T, second: U): T & U {
  2. let result = <T & U>{};
  3. for (let id in first) {
  4. (<any>result)[id] = (<any>first)[id];
  5. }
  6. for (let id in second) {
  7. if (!result.hasOwnProperty(id)) {
  8. (<any>result)[id] = (<any>second)[id];
  9. }
  10. }
  11. return result;
  12. }
  13. class Person {
  14. constructor(public name: string) { }
  15. }
  16. interface Loggable {
  17. log(): void;
  18. }
  19. class ConsoleLogger implements Loggable {
  20. log() {
  21. // ...
  22. }
  23. }
  24. var jim = extend(new Person("Jim"), new ConsoleLogger());
  25. var n = jim.name;
  26. jim.log();

联合类型(Union Types)

联合类型与交叉类型很有关联,但是使用上却完全不同。 偶尔你会遇到这种情况,一个代码库希望传入 numberstring类型的参数。 例如下面的函数:

  1. /**
  2. * Takes a string and adds "padding" to the left.
  3. * If 'padding' is a string, then 'padding' is appended to the left side.
  4. * If 'padding' is a number, then that number of spaces is added to the left side.
  5. */
  6. function padLeft(value: string, padding: any) {
  7. if (typeof padding === "number") {
  8. return Array(padding + 1).join(" ") + value;
  9. }
  10. if (typeof padding === "string") {
  11. return padding + value;
  12. }
  13. throw new Error(`Expected string or number, got '${padding}'.`);
  14. }
  15. padLeft("Hello world", 4); // returns " Hello world"

padLeft存在一个问题, padding参数的类型指定成了 any。 这就是说我们可以传入一个既不是 number也不是 string类型的参数,但是TypeScript却不报错。