どこで使えるのかはわからないけれど、ネストされたオブジェクトのプロパティをひたすらすべて列挙して、Union Typeにするワンライナーができたのでメモ
.ts
type ValueOf<T> = T[keyof T];
type Property<T> = keyof T | ValueOf<{[K in keyof T]: T[K] extends object ? Property<T[K]> : never}>
ワンライナーといいつつ2行あるのはご愛嬌
以下のような感じで使える
.ts
interface User {
name: string,
id: string,
obj: {
obj2: {
aaa: string
},
bbb: string,
}
}
type ValueOf<T> = T[keyof T];
type Property<T> = keyof T | ValueOf<{[K in keyof T]: T[K] extends object ? Property<T[K]> : never}>
type UserProperty = Property<User> //=> "name" | "id" | "obj" | "obj2" | "bbb" | "aaa"
ちなみにネストされているプロパティをチェックしなくて良いなら以下で事足りる
.ts
type Property<T> = keyof T //=> "name" | "id" | "obj"
深さ指定で所得できるようにする
もはやワンライナーではないけれど、以下のように書けば深さ指定でプロパティを所得できる
.ts
// 5階層まで対応。もっと深くまで辿りたい場合は 6:5 のように増やす
type NumMap = {
5:4,
4:3,
3:2,
2:1,
1:1,
}
type ValueOf<T> = T[keyof T];
type Property2<T,P extends keyof NumMap> = P extends 1 ? keyof T : ValueOf<{[K in keyof T]: T[K] extends object ? Property2<T[K], NumMap[P]> : never}>
以下のように使える
.ts
interface User {
name: string,
id: string,
obj: {
obj2: {
aaa: string
},
bbb: string,
}
}
type NumMap = {
5:4,
4:3,
3:2,
2:1,
1:1,
}
type ValueOf<T> = T[keyof T];
type Property2<T,P extends keyof NumMap> = P extends 1 ? keyof T : ValueOf<{[K in keyof T]: T[K] extends object ? Property2<T[K], NumMap[P]> : never}>
type UserProperty = Property2<User,2> //=> "obj2" | "bbb"
まとめ
TypeScriptすごい
参考