【问题标题】:TypeScript union with exclude and type guard带有排除和类型保护的 TypeScript 联合
【发布时间】:2018-12-27 21:37:35
【问题描述】:

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

我想知道这是 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

【问题讨论】:

    标签: typescript


    【解决方案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);
    }
    

    【讨论】:

      猜你喜欢
      • 2019-02-13
      • 2018-12-03
      • 2020-01-14
      • 1970-01-01
      • 2019-01-04
      • 2017-05-18
      • 1970-01-01
      • 2022-11-25
      • 1970-01-01
      相关资源
      最近更新 更多