ts类型体操之对象访问路径

280 阅读1分钟

从对象得到形如 '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>>