A延伸B;类型'Pick <a,exclude <keyof =“” a,=“” keyof =“” b =“” >>&B'不能分配给类型'A'.ts(2322)

时间:2019-05-16 22:47:41

标签: typescript

这是错误还是我误解了打字稿内容?

以下示例代码:

type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;

const func = <A extends B, B>() => {
  const aWithoutB: Omit<A, keyof B> = {} as any; // The {} assignment isn't important here.

  const b: B = {} as any;

  const a: A = {
    ...aWithoutB,
    ...b
  }; // warning here
};

使用TypeScript 3.4.5的IDE(VS代码)警告:

Type 'Pick<A, Exclude<keyof A, keyof B>> & B' is not assignable to type 'A'.ts(2322)

我认为这两种类型是相等的,但不是。是什么原因?

1 个答案:

答案 0 :(得分:4)

主要原因是,编译器目前doesn't perform进行这种类型的高阶类型分析,以使其了解未解析的通用对象类型与该类型的互补属性集的交集之间的等价关系。从链接问题的状态尚不清楚,是否会实施这种分析。毫无疑问,让编译器可以解决这些问题,但是谁知道在不降低编译器性能的情况下是否可以做到这一点?


第二个原因是这两种类型实际上不是等效的。考虑以下接口BetaAlpha

interface Beta {
    x: string | number,
    y: boolean,
    z?: object  
}

interface Alpha extends Beta {
    x: string,
    y: true,
    z: undefined
}

func<Alpha, Beta>(); // no error, but uh oh

declare const beta: Beta;
declare const alpha: Alpha;
const notAlpha: Alpha = { ...alpha, ...beta }; // error!

请注意,Alpha extends Beta,但是如果将Alpha和之后的Beta扩展到一个新对象中,您会得到一个{{1} }。因此,您可以致电Alpha,但您可能无法拨打电话。

毫无疑问,您专注于通过向其添加更多属性来扩展类型,但没有注意通过缩小现有属性的类型来扩展类型。


可以加强对func<Alpha, Beta>()A的约束以使其BA共享的任何键相互通过指定BA extends B来分配可分配的属性类型。对于B extends Pick<A, keyof A & keyof B>中的任何键Kkeyof A & keyof B表示A extends B,而A[K] extends B[K]表示B extends Pick<A, keyof A & keyof B>

在实现过程中,一旦您被精通的人类推理技术绝对确信B[K] extends A[K]Omit<A, keyof B> & B确实是同一回事(我希望如此),但是编译器不确信,您可以通过使用type assertion使您的情报掌握编译器。

让我们看看它的作用:

A

好的,希望能有所帮助。祝你好运!