151
104

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 5 years have passed since last update.

TypeScript で既にある型から一部を nullable にする型を作る

Last updated at Posted at 2019-02-19

こういう2つの型を扱うことがあると思います

type Article = {id: string, value: number}
type ArticleDraft = {id: string | null, value: number}

ORM などで一度保存するまでidが振られない、みたいな時によくある型ですね。

これは簡単な例ですが、フィールドが多くなると同じような型を2つ書くのが面倒くさいし、何よりバグを仕込みそうなので、今回はなんとかして Article 型から ArtcileDraft 型を最小限の手数で生成したい、と思います。

案1: Draft を先に定義して、 extends して絞り込む

interface ArticleDraft {id: null | string, value: number}
interface Article extends ArticleDraft { id: string }

意図したとおりの2つの型が出来たのですが、発想の順序が逆です。先に Article を宣言してから ArtcileDraft を生成したいので、別の手段をとります。

案2: Conditional Type の型魔法で nullable に変換

export type Draft<T, D extends keyof T> = { [K in keyof T]: (K extends D ? T[K] | null : T[K]) };

// Example
type Foo = { id: string }
type FooDraft = Draft<Foo, 'id'>
//   => {id: null | string}

Twitter であれこれしてたら @wonderful_panda 氏に教えてもらいました。

型のプロパティをイテレートして別の型を再構築しながら、第二型引数で渡した key を満たす型は nullable な型に変形しています。

これが便利なのは、 文字列の uniontype で複数の型を nullable にできること

type Article = {id: string, value: number}
type ArticleDraft = Draft<Article, 'id' | 'value'>
// => {id: string | null, value: number | null}

意味はわかるのですが、自分でこれをひねり出すことは出来ませんでした。とはいえイディオムの組み合わせなので、一度知ったら色々応用できそうなテクニックですね。

参考

151
104
0

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
151
104

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?