【问题标题】:TypeScript intersection types with array reduceTypeScript 交集类型与数组减少
【发布时间】:2017-06-12 23:04:06
【问题描述】:

我正在尝试让类型与通用数组 reduce 函数一起工作,该函数基本上合并了两个对象。以下 sn-p 是真实代码的转储版本。为什么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】:

    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 参数设置为IFoo | IBar
    4. flatten 的返回类型 (K &amp; T) 因此是 K &amp; (IFoo | IBar)
    5. 由于flatten 的返回类型必须可分配给U,这给了我们约束U &gt;= (U &amp; (IFoo | IBar)),它简化为U &gt;= (IFoo | IBar)
    6. 另一个证据是initialValue 参数,其类型为{}
    7. 所以U &gt;= {}
    8. 这两个约束的最小上限是{}。所以类型检查器推断U ~ {}

    为什么它没有意识到返回类型是IFoo &amp; IBar?类型检查器不会对代码的运行时行为进行推理 - flatten 的参数在整个缩减过程中采用各种不同的类型。 (IFoo | IBar)[] 类型的数组不能保证同时包含 IFoos 和 IBars - 它可能只是 IFoos 的数组。推断flattening 异构列表会压缩其构成类型将需要相当复杂的证明,并且期望机器能够为您编写这样的证明似乎是不合理的。

    【讨论】:

    • 很棒的答案!非常感谢详细的解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 2020-06-27
    • 1970-01-01
    • 2020-10-01
    相关资源
    最近更新 更多