abcdefGets

ゲッツ!

Typescript 2.2 変更点

Typescript 2.2がでた。

変更点が少々あるので確認しておきたい。

Mixinのサポート

遂にMixinがサポートされた。やり方が少々直感的ではないけども。

公式のサンプルコードで確認する。

class Point {
    constructor(public x: number, public y: number) {}
}

class Person {
    constructor(public name: string) {}
}

type Constructor<T> = new(...args: any[]) => T;

function Tagged<T extends Constructor<{}>>(Base: T) {
    // 今まではここでエラーになっていた。
    return class extends Base {
        _tag: string;
        constructor(...args: any[]) {
            super(...args);
            this._tag = "";
        }
    }
}

const TaggedPoint = Tagged(Point);

let point = new TaggedPoint(10, 20);
point._tag = "hello";

class Customer extends Tagged(Person) {
    accountBalance: number;
}

let customer = new Customer("Joe");
customer._tag = "test";
customer.accountBalance = 0;

上のコードのnew(...args: any[]) => TがMixinのコンストラクタとして認識され、
Tagged関数内で無名クラスでnew(...args: any[]) => Tを継承することが許されるようになった。

type Constructor<T> = new(...args: any[]) => T;

function Loggable<T extends Constructor<{}>>(Target: T) {
    return class extends Target {
        protected log(content: string) {console.log(content)}
    }
}

class Base {}

class Derived extends Loggable(Base) {
  public doSomething() {
    this.log('...');
  }
}

みたいにTrait的な感じで使える。

object型のサポート

今までのtypescriptはnumber | string | boolean | symbol | null | undefined以外にPrimitive型を持っていなかったが、
今回からobject型が追加された。object型は上記のPrimitive型以外の全てに対応する。

これも公式のサンプルだが、

declare function create(o: object | null): void;

create({ prop: 0 }); // OK
create(null); // OK

create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error

のような感じ、要はPrimitive以外を受け付けるanyのような感じか。

new.targetのサポート

new.targetがtypescriptでもサポートされた。
あまり使う機会は無いが、例ではErrorの継承があげられている。

class CustomError extends Error {
    constructor(message?: string) {
        super(message); // 'Error' breaks prototype chain here
        Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
    }
}

ErrorだけでなくArray等の、
constructorを単純に呼び出すだけではうまく継承できないビルトインクラスを継承する場合に使う。

null/undefinedチェックの強化

式中のnull/undefinedのチェックが強化された。
以下の場合はエラーになる。

  • もし、+オペレーターのオペランドがnullableで、オペランドがstringでもanyでも無いとき。
  • もし、-, *, **, /, %, <<, >>, >>>, &, |, ^オペランドがnullableのとき。
  • もし、<, >, <=, >=, inオペランドがnullableのとき。
  • もし、instanceof の右辺がnullableのとき。
  • もし、+, -, ~, ++, -- の単項がnullableのとき。

stringをキーにしたオブジェクトにドットでアクセスできるようになった

以下のような型

interface StringMap<T> {
    [x: string]: T;
}

にたいしてドットでプロパティアクセスしてもOKになった。

var stringMap: StringMap;
stringMap.foobar; // ok
stringMpa['foobar']; // ok

jsxの子要素に対するspreadオペレーターがサポートされた。

これも公式の例を拝借

function Todo(prop: { key: number, todo: string }) {
    return <div>{prop.key.toString() + prop.todo}</div>;
}

function TodoList({ todos }: TodoListProps) {
    return <div>
        {...todos.map(todo => <Todo key={todo.id} todo={todo.todo} />)} //ここ!
    </div>;
}

let x: TodoListProps;

<TodoList {...x} />

のように、直接子要素を展開する構文がサポートされた。

jsx: react-nativeがサポートされた

これはそのまま。
react-nativeでコンパイルすると、jsx構文がそのまま残った上でjsの拡張子になる。

まとめ

Mixinが嬉しい!