46
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Organization

TypeScript: UnionToIntersection<T> ─ 共用体型を交差型にするユーティリティ型

本稿ではTypeScriptで、共用体型(union type)を交差型(intersection type)に変形するmapped typesを紹介します。

共用体型を交差型に変換するmapped types

type UnionToIntersection<U> =
  (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;

出典はTypescript Convert Union to intersection - Stack Overflowです。一応上のスニペットは、Stack Overflowの回答からの原文ママの引用なので、ライセンスは回答にあるソースコードを別の場所で使っても構いませんか? - スタック・オーバーフローMetaを参照してください。

使い方

まず交差型にしたい共用体型を準備します。ここではEither(どっちかという意味)という型を用意しました。{a: number}{b: number}のどちらかを満たせばOKなやつです。

type Either = {a: number} | {b: number}

念の為、共用体型の性質を確認しておきます。

const a: Either = {} // Compile error: Property 'a' is missing 
const b: Either = {a: 1}
const c: Either = {b: 1}
const d: Either = {a:1, b: 1}

上のコードではaだけが型を満たせないのでコンパイルエラーになります。

次に、先程のUnionToIntersectionを使って上のEitherから、{a: number} & {b: number}を錬成したいと思います。ここではBoth(どちらもの意)という型名にします。

type Both = UnionToIntersection<Either>

ちゃんと交差型になっているか確認します。

const p: Both = {} // Compile error: Property 'a' is missing 
const q: Both = {a: 1} // Compile error: Property 'b' is missing
const r: Both = {b: 1} // Compile error: Property 'a' is missing
const s: Both = {a:1, b: 1}

上のコードのs以外がコンパイルエラーになりました。ちゃんと交差型になっているようです。

この検証をやってみたい方はTypeScript playgroundで試せます。

解説

いろいろ試行錯誤はしてみましたが、ついになぜ動くのか理解できませんでした。説明できる方、いましたら教えてください :pray:

uhyoさんからコメントで解説いただきました。

実用例

このテクニックの実用例を @kahirokunn に教えてもらいました。VuexにmapComputedのようなヘルパー関数を定義するときに応用すると、型安全なコードが書けるようです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
46
Help us understand the problem. What are the problem?