Swiftに慣れるとどうしても Generics でclassの定義をしたくなりませんか?
Firebase Cloud Functionsを初めてからとことんTypeScriptを書くことが多くなってきたのでちょっとしたTipsを紹介します。
この文章はあくまでもSwiftに慣れた人がTypeScriptを書く場合のコツです。TypeScript本家の方でもっといい方法を知っている方がいればぜひご教示下さい。
ProtocolとInterface
SwiftのProtocolに相当するTypeScriptの構文はInterfaceです。
TypescriptのInterfaceはSwiftのProtocol Extension
ができないなど物足りなさも感じますが、Classに必要なプロパティやファンクションを定義する意味では充分に機能します。
protocol AProtocol {
}
interface AProtocol {
}
ここまでは非常に似ているが。。
Genericsをつけると途端にわかりにくい
さぁこれにGenericsを加えていきましょう。
Swift
protocol AProtocol {
init()
}
protocol BProtocol {
associatedtype A: AProtocol
}
class Fuga: AProtocol {
required init() {}
}
class Hoge<T: AProtocol>: BProtocol {
typealias A = T
func fuga() -> A {
let a: A = A()
return a
}
}
let hoge: Hoge<Fuga> = Hoge()
let a: Fuga = hoge.fuga()
TypeScript
interface AProtocol {
}
interface BProtocol<A extends AProtocol> {
}
class Fuga implements AProtocol {
}
class Hoge <A extends AProtocol> implements BProtocol<A> {
private _A: { new(): A }
fuga(): A {
const a: A = new this._A()
return a
}
}
const hoge: Hoge<Fuga> = new Hoge()
const a: Fuga = hoge.fuga()
考え方を整理するポイントは2つ
associatedtype
{ new(): A }
TypeScriptでassociatedtype
っぽいことをする
Swiftのassociatedtype
は、TypeScriptでは BProtocol<A extends AProtocol>
のように依存するプロトコルを宣言します。
Genericsの型を初期化
TypeScriptでGenericsの型を初期化するには{ new(): A }
が必要です。Swiftのassociatedtype
の代わりに
private _A: { new(): A }
を宣言しています。こうすることでclass内ではどこでもA
を初期化することが可能になります。