LoginSignup
8
5

More than 5 years have passed since last update.

Mapped Typeを使って、Partial typeからStrict typeを生成する

Last updated at Posted at 2016-12-08

2016.12.12 追記

コメントにある通り、この挙動は意図したものではないようです。(Nightly 2.2.0 dev.20161211で挙動も変わったようです)
残念ですが、今のところPartial TypeからStrict Typeを得る一般的な方法はないようです。

もともとの動機は、下のような2つの型を別々に書きたくないという話だったのですが、

type PersonPartial = { name: string, age?: number, gender?: "male"|"female" };
type PersonStrict = { name: string, age: number, gender: "male"|"female" };

とりあえず、

type PersonRequired = { name: string };
type PersonOptional = { age: number, gender: "male"|"female" };
type PersonPartial = PersonRequired & Partial<PersonOptional>;
type PersonStrict = PersonRequired & PersonOptional;

とでもするしかなさそうです。


TypeScript 2.1がリリースされました。
やはり keyof / Mapped type の注目度が高いようで、qiitaにもネタが集まりつつありますね。いいことです。

TypeScript 2.1のkeyofとかMapped typesがアツい
TypeScript 2.1 で setState() が型安全になるぞー

やりたいこと

さて、以下のような2つの型があるとします。1

type PersonStrict = { name: string, age: number };
type PersonPartial = { name?: string, age?: number };

Partial<T> を使えば、 PersonPartial は以下のように PersonStrict から得ることができるというのは、上に挙げた「TypeScript 2.1 で setState() が型安全になるぞー」でも紹介されていました。

type PersonPartial = Partial<PersonStrict>;

では、逆に PersonPartial から PersonStrict を得ることはできるでしょうか? 2

type Strict<T> = ???; // これをどう定義すれば、下のように PersonStrict を得られるか?
type PersonStrict = Strict<PersonPartial>;

こたえ

素直に考えると、これ(↓)でできそうな気がします。が、実際にやってみると、これでは各メンバは省略可能なままです。

type Strict<T> = { [K in keyof T]: T[K] };
const person: Strict<PersonPartial> = { name: "iwata" }; // 代入できてしまう

ですが、これに () をおまじないとして付加すると、見事に strict typeに変わりました。

type Strict<T> = { [K in (keyof T)]: T[K] };
const person: Strict<PersonPartial> = { name: "iwata" }; // age がないというエラーになる

TypeScript面白いですね。

なぜそうなる?

正直に言うと、分かりません。

想像でしかないですが、一つ目の例の [K in keyof T] というのはそれ自体が一つのイディオムで、この場合に限り省略可能かどうかをMapped typeに引き継ぐための処理がなされているのではないかなあと。
これに()をつけて、keyof T を先に評価させることで、「Tのプロパティ名」ではなく「単なる "name" と "age" の直和型」に意味が変わるので、省略可能かどうかという情報が欠落するということかなあと考えています。
ご存じの方がいたら教えてください。

免責事項

ドキュメント上にこの挙動に関する記述を見つけることはできなかったので、実はこれは仕様ではなくて不具合だったみたいな話になるかもしれません。
その場合はごめんなさい。

脚注


  1. PersonPartial のような全てのメンバを省略可能にした型を「Partial type」と呼ぶのはドキュメントにも登場する呼び方なのですが、逆に全てのメンバを省略不可にした型をなんと呼ぶべきかは見当たらなかったので、とりあえずこのエントリでは「Strict type」と呼ぶことにしています。 

  2. なんでそんなことをしたいのかはまた別の機会に。 

8
5
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
8
5