具有数组reduce的TypeScript交集类型

时间:2017-01-27 09:48:52

标签: typescript types reduce

我正在尝试使用泛型数组reduce函数进行打字,它基本上合并了两个对象。以下代码段是真实代码的转储版本。为什么fl的类型为{}而非IFoo & IBar

(我知道可以通过一次Object.assign()调用轻松替换此特定示例。)

const flatten = <K, T>(prev: K, x: T): K & T => {
  return Object.assign(prev, x);
};

interface IFoo {
  foo: true;
}

interface IBar {
  bar: true;
}

const fooRes: IFoo = { foo: true };
const barRes: IBar = { bar: true };

const fl = [fooRes, barRes].reduce(flatten, {});

console.log(fl); // here, fl : {}

1 个答案:

答案 0 :(得分:4)

The signature of reduce

reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U

T是数组本身的类型参数。)所以,面对代码

[fooRes, barRes].reduce(flatten, {})

类型检查器的工作是找出U是什么。让我们来看看它的推理:

  1. fooRes : IFoobarRes : IBar,所以[fooRes, barRes] : (IFoo | IBar)[]
  2. 因此,数组T ~ IFoo | IBar
  3. 因此flatten参数设置为T
  4. ,因此调用IFoo | IBar
  5. flatten的返回类型(K & T)因此为K & (IFoo | IBar)
  6. 由于flatten的返回类型必须可分配给U,因此会为我们提供约束U >= (U & (IFoo | IBar)),简化为U >= (IFoo | IBar)
  7. 另一点证据是initialValue参数,其类型为{}
  8. 所以U >= {}
  9. 这两个约束的最小上限是{}。因此,类型检查器会推断U ~ {}
  10. 为什么它没有意识到返回类型是IFoo & IBar?类型检查器不会对代码的运行时行为进行推理 - flatten的参数在整个减少过程中采用各种不同的类型。类型(IFoo | IBar)[]的数组不保证同时包含IFooIBar - 它可能只是IFoo的数组。推断flatten异构列表压缩其构成类型需要相当复杂的证据,并且期望机器能够为您编写此类证据似乎并不合理。