Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

TypeScript 2.1のkeyofとかMapped typesがアツい

TypeScript 2.1のkeyofとかMapped typesがアツい

by Quramy
1 / 14

About me


  • フロントエンドエンジニア的なことをして生きています。
  • TypeScript + AngularでSPA作ってます。

2.1 RC is coming!

2016.11.08現在、2.1 RCがリリースされた。
TypeScript blogによると、

  • async/awaitのDown transpileがES5/ES3でも利用可能に(~2.0ではES2015以上をtargetにしないと使えなかった)
  • 型推論がより賢くなった


2.1.1にどのような変更が入ったかは、 @vvakame先生の記事 に詳しく記載されてる


2.1のRoadmap を読むと、

  • Static types for dynamically named properties
  • Mapped types


Static types for dynamically named properties


feature 名長い。。。


このfeatureでは、keyofという新しいキーワードと、T[K] という2つの記法が追加された。


keyof T で「type Tのプロパティ名の直和型」を表現するtypeが記述できる

interface User {
  name: string;
  age: number;

type UserKey = keyof User;

と書くと、 UserKey'name' | 'age' というtypeになるよ、ということ。


T[K] で「T に対してK型でアクセスして得られるtype」を表現できる

K は、keyof T を満たすtypeであれば良いので、例えば

type UserName = User['name'];

とすると、UserName のtypeは string になる。 User['age'] とすれば number


interface Observable<T> {
    pluck<K extends keyof T>(key: K): Observable<T[K]>;

let user$: Observable<User>;
let name$ = user$.pluck('name'); // Observable<string>

以前は name$ = user$.pluck<string>('name') のように、動的にアクセスした先の型情報を自分で補う必要があった。

Mapped types



{[P in K]: T}

という記法が可能に。K は stringにアサイン可能なtypeであればよく、 K に対する値は T というtypeになるよ、と言う意味。

type Item = { a: string, b: number, c: boolean };

type T1 = { [P in "x" | "y"]: number };  // { x: number, y: number }
type T2 = { [P in "x" | "y"]: P };  // { x: "x", y: "y" }
type T3 = { [P in "a" | "b"]: Item[P] };  // { a: string, b: number }
type T4 = { [P in keyof Item]: Date };  // { a: Date, b: Date, c: Date }
type T5 = { [P in keyof Item]: Item[P] };  // { a: string, b: number, c: boolean }
type T6 = { readonly [P in keyof Item]: Item[P] };  // { readonly a: string, readonly b: number, readonly c: boolean }
type T7 = { [P in keyof Item]: Array<Item[P]> };  // { a: string[], b: number[], c: boolean[] }

Mapped typesにより、既存typeのkey情報を再利用しつつ、新しいtypeを定義することができる:

type Freeze<T> = {
    readonly [P in keyof T]: T[P];

let frozenUser: Freeze<User>;
frozenUser.age = 18; // error TS2540: Cannot assign to 'age' because it is a constant or a read-only property.


オブジェクトの各key & valueに対して処理を行う関数の定義:

declare function mapObject<K extends string, T, U>(
  obj: {[P in K]: T},
  fn: (x: T, k?: K) => U
): {[P in K]: U};

const nameLengths= mapObject({
    firstName: 'Yosuke',
    lastName: 'Kurami'
}, (x => x.length));

// type of nameLengths: { firstName: number, lastName: number};

なお、type Record<K extends string, T> = {[P in K]: T} というtypeがlib.es6.d.tsに定義済み.


Boxingのサンプル(Angular2のReactive FormGroupを題材にしました)

interface FormControl<S> {
    setValue(value: S): void;
    reset(): void;
    valueChanges: Observable<S>;
    /* etc... */

type FormControls<T, K extends keyof T> = {[P in K]: FormControl<T[P]>};

interface FormGroup<T, K extends keyof T> {
    controls: FormControls<T, K>;
    set(v: Partial<T>): void;

declare var formBuilder: {
    group<T, K extends keyof T>(obj: T): FormGroup<T, K>;

const user: User = {
    name: 'Quramy',
    age: 32,

const formGroup = formBuilder.group(user);
controls.name.valueChanges.subscribe(x => {/** ... */});

name をboxingした FormControl(controls.name)は、name の型に従って、Observable<string> が返ってくる


  • TypeScript 2.1.4では、動的にプロパティを扱う関数の型定義が書きやすくなった
  • コレクションやオブジェクトを操作する関数・ライブラリをより賢く記述できるようになった
  • Immutable.jsやRx、lodash 等がより改善される...かも?


TypeScript 2.1ではLanguage Service関連の機能追加(quickfix, implementation jump等)も含まれるので、


2.1.4(2.1系安定版) のリリース案内 https://blogs.msdn.microsoft.com/typescript/2016/12/07/announcing-typescript-2-1/ では、keyofやMapped Typesにも触れられています。

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
Help us understand the problem. What are the problem?