実行環境
$ tsc --version
Version 2.7.2
コード
interface IUser {
name: string;
}
class BaseUser implements IUser {
name: string;
constructor(initial: Partial<IUser>) {
(<any>Object).assign(this, initial);
}
static createCollection<T extends BaseUser>(
this: {new(initial): T},
collectionData
): T[] {
const collection: T[] = [];
collectionData.forEach(data => {
const initialData = data as IUser;
collection.push(new this(initialData));
});
return collection;
}
}
class Manager extends BaseUser {
}
class Programmer extends BaseUser {
}
const array = [
{name: 'test1'},
{name: 'test2'},
]
const managers = Manager.createCollection(array)
console.log(managers) // => [ Manager { name: 'test1' }, Manager { name: 'test2' } ]
const programmers = Programmer.createCollection(array)
console.log(programmers) // => [ Programmer { name: 'test1' }, Programmer { name: 'test2' } ]
User
の初期値のオブジェクトの配列などを渡したら、Userクラスインスタンスの配列が返ってきて欲しいときにつかいたいやつ。
肝心のそのstaticメソッドは createCollection
基底クラスなどにこのメソッドを仕込んでおけば、いちいちクラスを渡すこと無く、基底クラスの継承先クラスのインスタンスが返ってきて便利。
なにをやってるのか
this: {new(initial): T}
functionの第一引数にthisとその型を渡すと、自分でthisの型を決定できる。
https://www.typescriptlang.org/docs/handbook/functions.html#this-parameters
さらに、コンストラクタシグネチャを使って、Tというconcrete classのインスタンスを返すコンストラクタを持つオブジェクト型をthisの型として指定する。
単純に this: T
などとすると error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
というエラーがでてしまうので、ちょっと回りくどい感じになってる。
参考issue
この書き方はTypeScriptのissuesを参考にしてる。
https://github.com/Microsoft/TypeScript/issues/5863
issueが長すぎるので、みんな結構staticでいい感じにthisを使うのは苦労してるみたい…
別解
static createCollection<T extends BaseUser>(
this: new (initial) => T,
collectionData
): T[] {
こういう書き方でも同じような結果になるけど new (initial) => T
の部分がどういう書き方なのか、何故こうなるのかが分からない…ご存じの方いたら教えてください