10 一文搞定TypeScript交叉类型

107 阅读1分钟

基础

交叉类型的目的?

合并两个类型

  type Person = {
    name: string
  }
  type Car = {
    wheel: number
  }
  type PersonCar = Person & Car

  const a: PersonCar = {
    name: 'jack',
    wheel: 4
  }

实战

怎样实现合并两个对象的属性?

function extend<T extends object, U extends object>(first: T, second: U): T & U {
  const result = <T & U>{};
  for (let id in first) {
    result[id] = first[id];
  }
  for (let id in second) {
    if (!result.hasOwnProperty(id)) {
      result[id] = second[id];
    }
  }

  return result;
}

const x = extend({ a: 'hello' }, { b: 42 });

// 现在 x 拥有了 a 属性与 b 属性
const a = x.a;
const b = x.b;

这样写的话会报错
截屏2022-08-30 23.11.49.png

关键错误 [id]的类型是 T[Extract<keyof T, string>]
result[id]的类型是 (T & U)[Extract<keyof T, string>]

这下目标缩小为怎么从 (T & U) 得到 T类型,可以通过如下方式实现

const result = <T>(<T & U>{});

改良后的版本

function extend<T extends object, U extends object>(
  first: T,
  second: U
): T & U {
  const result = <T & U>{};
  for (let key in first) {
    (<T>result)[key] = first[key];
  }

  for (let key in second) {
    // 去除重复的key
    if (!result.hasOwnProperty(key)) {
      (<U>result)[key] = second[key];
    }
  }
  return result;
}

更简单的 extend ?

function extend<T extends bject,U extends object>(first: T,second: U): T & U {
  return { ...first, ...second}
}