63
46

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-08-20

本稿では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のようなヘルパー関数を定義するときに応用すると、型安全なコードが書けるようです。

63
46
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
63
46

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?