具有排除和类型防护的TypeScript联合

时间:2018-12-27 13:03:43

标签: typescript

为什么下面的代码有错误?

我想知道这是TypeScript编译器的错误。

type A =
  | {
      type: 'a';
      a: string;
    }
  | {
      type: 'b';
      b: string;
    };

type X = {
  x: string;
} & A;

type XX = Pick<X, Exclude<keyof X, 'x'>> & {
  x: number;
};

const x: XX = {} as any;

if (x.type === 'a') {
  // Property 'a' does not exist on type 'XX'
  console.log(x.a);
}

You can try this code on TypeScript Playground

1 个答案:

答案 0 :(得分:1)

您看到的只是联合类型如何工作的结果。联合(除非缩小)仅允许访问公共属性。因此,当您说keyof X时,将在结果字符串文字联合中出现的唯一属性是x(不依赖于联合)和type,这两个联合成员都共有。 Pick在后​​台也使用keyof,因此存在相同的问题,它将能够选择所有工会成员共有的工会成员。

您可以得到所需的行为,但不能直接使用keyofPick。您需要在带裸类型参数的条件类型中使用。条件类型将分布在工会的成员上(您可以了解更多关于此行为的here或更简洁的版本here),从而使我们可以在每个成员上应用keyofPick工会成员,而不是整个工会。

type A =
  | {
      type: 'a';
      a: string;
    }
  | {
      type: 'b';
      b: string;
    };

type X = {
  x: string;
} & A;


type UnionKeys<T> = T extends any ? keyof T : never;
type UnionPick<T, K extends UnionKeys<T>> = T extends any ? Pick<T, Extract<K, keyof T>> : never 
type XX = UnionPick<X, Exclude<UnionKeys<X>, 'x'>> & {
  x: number;
};

const x: XX = {} as any;

if (x.type === 'a') {
  console.log(x.a);
}