TypeScript 4.1から導入される、Template Literal Typesを使って遊んでみました。
今回やったこと
例えば、APIなどからは下のようにidとして受け取って
interface RelationsAreIdEntity {
categoryId: number
groupId: number
}
IDを途中でオブジェクトに変換し、最終的には下のようなクラスにすることがあるとおもいます。
interface Category {}
interface Group {}
interface Entity {
category: Category
group: Group
}
この時RelationsAreIdEntityとEntityを見ると、フィールド名と型がほとんど同じで、2回同じようなことを書くのが馬鹿らしく感じます。また、この例では1クラスかつ2フィールドだけですが、このフィールドや、クラスがどんどん増えてきたら、いちいちそれぞれのクラスをメンテするのも面倒になってきます。
なので、これをTemplate Literal Typesを使って手抜きする方法を試しました。
結果
type IdFields = `${keyof Entity}Id`
type RelationsAreId = {
[K in IdFields]: number
}
これだけで、RelationsAreIdが、RelationsAreIdEntityと同じ定義になります。
実際に使ってみると
const correct: RelationsAreId = {
categoryId: 1,
groupId: 2
}
// CompileError: groupIdが無い
const compileError1: RelationsAreId = {
categoryId: 1
}
// CompileError: categoryIdがnumberじゃない
const compileError2: RelationsAreId = {
categoryId: "aaaa"
}
// CompileError: categoryIdが無い
const compileError3: RelationsAreId = {
category: 1,
groupId: 2
}
こんな感じになります。