从对象得到形如 'a.b.c' 的对象访问路径字符串,不支持数组
预览结果 ts playfround
/**
* 将对象由 key:vlaue 转化为 key:key
*/
type ReplaceValueByKey<T> = {
[key in keyof T]: T[key] extends object ? ReplaceValueByKey<T[key]> : key
}
/**
* 将形如 {key:key,key2:{key3:key3}} 的类型 转化为 key| key2 | key2.key3
*
* @example
* type E = ObjectPath1<{'name':'name',test:{value:'value'}}> // "name" | "test" | "test.value"
*/
type ObjectPath1<T> = {
[key in keyof T]: T[key] extends infer R ? R extends string ? T[key] : (key | _ObjectPath<key extends string ? key : '', T[key]>) : never
}[keyof T]
/**
* 生成 形如 T.valueOf V 的联合类型
*
* @example
* type E = {name:'name',parent:{name:'tom',age:'age'}}
* type F = _ObjectPath<'parent',E['parent']> // "parent.tom" | "parent.age"
*/
type _ObjectPath<T extends string, V> = `${T}.${V[keyof V] extends string ? V[keyof V] : (_ObjectPath<keyof V extends string ? keyof V : '', V[keyof V]>)}`
/**
* 对象访问路径生成联合类型
*
* @example
* interface Base {
* base: 'base'
* }
*
* interface Test extends Base {
* bb: string
* }
*
* interface User extends Base {
* name: string
* age: number,
* test: Test
* }
* type E = ObjectPath<User>
* //type E = "name" | "age" | "test" | "base" | "test.base" | "test.bb"
*/
type ObjectPath<T> = ObjectPath1<ReplaceValueByKey<T>>