TypeScript 与数组reduce 的交集类型

问题描述 投票:0回答:1

我正在尝试让类型与通用数组归约函数一起使用,该函数基本上合并两个对象。以下代码片段是真实代码的转储版本。为什么

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 : {}
typescript types reduce
1个回答
11
投票

reduce
的签名是

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

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

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

类型检查器的工作是找出

U
是什么。让我们来看看它的推理:

  1. fooRes : IFoo
    barRes : IBar
    ,所以
    [fooRes, barRes] : (IFoo | IBar)[]
  2. 因此,数组的
    T ~ IFoo | IBar
  3. 因此
    flatten
    正在被调用,其
    T
    参数设置为
    IFoo | IBar
  4. 因此
  5. flatten
    的返回类型 (
    K & T
    ) 是
    K & (IFoo | IBar)
  6. 由于
    flatten
    的返回类型必须可分配给
    U
    ,这给了我们约束
    U >= (U & (IFoo | IBar))
    ,它简化为
    U >= (IFoo | IBar)
  7. 另一个证据是
    initialValue
    参数,其类型为
    {}
  8. 所以
    U >= {}
  9. 这两个约束的最小上限是
    {}
    。所以类型检查器推断出
    U ~ {}

为什么它没有意识到返回类型是

IFoo & IBar
?类型检查器不会推理代码的运行时行为 -
flatten
的参数在整个归约过程中采用各种不同的类型。
(IFoo | IBar)[]
类型的数组不能保证同时包含
IFoo
IBar
- 它可能只是一个
IFoo
数组。推断出异构列表会压缩其构成类型需要相当复杂的证明,并且期望机器能够为您编写这样的证明似乎并不合理。
    

© www.soinside.com 2019 - 2024. All rights reserved.