⌨️

TypescriptでUnionにOmitして共通ではないプロパティが消えてこまったら

2022/02/01に公開

多分Pickとかでもそうなんだけど、UnionにOmitすると共通ではないプロパティは消えます。
そこで Distributive conditional typeを使って丁寧にOmitする必要がある。

消える例

type UnionType =
  | {
      a: true;
      b: Record<string, unknown>; //これが後で消える
    }
  | {
      a?: false;
    };

type ComplexType = {
  id: string;
  name: string;
} & UnionType;

type TypeWithoutName = Omit<ComplexType, 'name'>;

const a1: UnionType = {} as any;
const a2: ComplexType = {} as any;
const a3: TypeWithoutName = {} as any;

if (a1.a) {
  console.log(a1.b);
}
if (a2.a) {
  console.log(a2.b);
}
if (a3.a) {
  console.log(a3.b); // TS can't find b because of Omit ???
}

消えない例 from stack overflow

type DistributiveOmit<T, K extends keyof any> = T extends any
  ? Omit<T, K>
  : never;
  
type TypeWithoutName = DistributiveOmit<ComplexType, 'name'>;

const a4: TypeWithoutName = {} as any;
if (a4.a) {
  console.log(a4.b); // Okay !
}

イメージとしては、 Omit<A | B | C, Key>Omit<A, Key> | Omit<B, Key> | Omit<C, Key> とする必要があるということ。
集合の演算として交換法則が成り立たないってことなんだなこれ。

Discussion

ログインするとコメントできます