36
17

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でオブジェクトの一部のプロパティのみ省略可能にする

Last updated at Posted at 2020-05-20

Data1
interface Data1 {
  foo: number
  bar: string
  baz: string
}

このData1というinterfaceに対して

const value: Data1 = {
  foo: 1,
  bar: "bar"
}

このように変数valueを定義すると当然コンパイルエラーになります。
このエラーを解消する方法として、各プロパティをnullableにしてしまう方法があります。
TSの標準ライブラリにはPartialがあり、これを使うとData1

Data2
interface Data2 {
  foo?: number
  bar?: string
  baz?: string
}

として扱えるようになります。
ただ、全てのプロパティを問答無用でnullableにするよりは、以下のように一部だけnullableとして扱えるようにすべきケースの方が多いかと思います。例えば以下のように扱いたい場合です。

Data3
interface Data3 {
  foo?: number
  bar?: string
  baz: string
}

ここで、Data1の構造を維持したままData3のように扱えるようにするためのオブジェクト操作系PartiallyPartialを実装する方法について書きます。

方法

TypeScript標準ライブラリのPartialを利用して以下のように書くと実現できます。

PartiallyPartialの定義

type PartiallyPartial<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

この後の構文解説では以下の使用例を用いていきます。

使用例
interface Data {
  foo: number
  bar: string
  baz: string
}
/*
 * T1は { foo?: number; bar?: string; baz: string } 型になる
 */
type T1 = PartiallyPartial<Data, 'foo' | 'bar'>

const value1: T1 = {
  baz: "baz"
}

console.log(value1)

構文解説

PartiallyPartialの定義を分解して見ていきます。

PartiallyPartial<T, K extends keyof T>

keyof Ttype Tのプロパティ名の直和型を表しています。
K extends keyof Tについてですが、このように記述することでKTの部分型であるという制約をつけることができます。
使用例においてこの構文の実体はPartiallyPartial<Data, 'foo' | 'bar'>であり、keyof T'foo' | 'bar'となります。

Omit<T, K>

Tの中からKに当てはまるプロパティのみを抽出した型を返します。
使用例においてこの構文の実体はPick<Data, 'foo' | 'bar'>であり、'foo' | 'bar' | 'baz'から'foo' | 'bar'を抜き取った{baz: boolean}を返してきます。

Partial<Pick<T, K>>

Partialは、冒頭でも述べたように全てのプロパティをnullableにする操作系です。
ここではPick<Data, 'foo' | 'bar'>'foo' | 'bar'をnullableにしています。つまりData型のプロパティの中で唯一'baz'だけがnullableでなくなります。最終的に返ってくる値は{foo?: number; bar?: string}になります。

Omit<T, K> & Partial<Pick<T, K>>

これはつまり{baz: boolean}{foo?: number; bar?: string}の積になるので、
{ foo?: number; bar?: string; baz: string }という型になります。

応用

Omitの逆であるPickは、型Tの中からKに当てはまるプロパティを除外した型を返すので、Tで指定したプロパティ以外を省略可能にすることが可能です。

type PartiallyPartial<T, K extends keyof T> = Pick<T, K> & Partial<Pick<T, K>>;
使用例
interface Data {
  foo: number
  bar: string
  baz: string
}
/*
 * T2は { foo: number; bar: string; baz?: string } 型になる
 */
type T2 = PartiallyPartial<Data, 'foo' | 'bar'>

const value2: T2 = {
  foo: 1,
  bar: "bar",
}
36
17
2

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
36
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?