A 扩展 B;类型 'Pick<A, Exclude<keyof A, keyof B>> & B' 不可分配给类型 'A'.ts(2322)

Zac*_*ack 3 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
};

Run Code Online (Sandbox Code Playgroud)

TypeScript 3.4.5 的 IDE (VS Code) 警告:

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

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

jca*_*alz 5

主要原因是编译器目前没有执行那种为了理解未解析的泛型对象类型与该类型的互补属性集的交集之间的等价性所必需的高阶类型分析。从相关问题的状态来看,是否会实施此类分析尚不清楚;毫无疑问,让编译器负责这些事情是可能的,但谁知道它是否可以在不降低编译器性能的情况下完成?


次要原因是,这两种类型是实际等效。考虑以下接口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!
Run Code Online (Sandbox Code Playgroud)

请注意Alpha extends Beta,但是如果您将 anAlpha后跟 a分散Beta到一个新对象中,则不会得到Alpha. 所以你可以打电话,func<Alpha, Beta>()但你可能不应该打电话。

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


可以收紧制约A,并B使它使双方共享的任何按键AB具有相互可分配的属性类型,通过指定A extends BB extends Pick<A, keyof A & keyof B>。对于任何关键Kkeyof A & keyof BA 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这与A(我希望)完全相同,但编译器不相信,您可以通过使用类型断言来控制编译器的智能。

让我们看看它的实际效果:

// more strict constraint
const func = <A extends B, B extends Pick<A, keyof A & keyof B>>() => {
    const aWithoutB: Omit<A, keyof B> = {} as any;
    const b: B = {} as any;    
    const a = {
        ...aWithoutB,
        ...b
    } as A; // I'm smarter than the compiler 
};

func<Alpha, Beta>(); // error now, as desired
func<Beta & { extraProp: string }, Beta>(); // okay
Run Code Online (Sandbox Code Playgroud)

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