用于将 "flattened" 对象的键递归重新映射到嵌套键中的类型(使用模板文字)
Type for recursively remapping keys of "flattened" object into nested one (using template literals)
我正在尝试将类型表达为一个函数,该函数接受一个带有键的对象作为点分隔路径和 returns 一个新对象,其中所有子路径都被扩展。我无法理解如何在递归 'de-structuring' 它们的同时保留给定路径的原始类型。
// Dummy structure
const flattenedObject = {
'd.a': 1,
'd.b': true,
};
type FlattenedObject = typeof flattenedObject;
// Expected type (or union of sub-paths: `{ d: { a: number } } | { d: { b: boolean } }`)
interface NestedObject {
d: {
a: number;
b: boolean;
}
}
// Attempt
type MapNestedKeys<R, N extends keyof R = keyof R, N0 = N> = N0 extends string
? N0 extends `${infer K1}.${infer K2}`
? { [K in N as `${K1}`]: MapNestedKeys<R, N, K2> }
: { [K in N as N0]: R[K] }
: {};
// Gives union, but types for nested keys are now union on all key types
type Test = MapNestedKeys<FlattenedObject>;
已更新
// Dummy structure
const flattenedObject = {
'a.b.c.d.e': 1,
'f.g.h.j.k': true,
};
type FlattenedObject = typeof flattenedObject;
type Values<T> = T[keyof T]
type MakeObj<Prop, Value> =
Prop extends string ?
Prop extends `${infer Head}.${infer Tail}` ?
{ [Key in Head]: MakeObj<Tail, Value> }
: Prop extends string ? { [K in Prop]: Value }
: never
: never
type Iterate<Obj> = Values<{
[Prop in keyof Obj]: MakeObj<Prop, Obj[Prop]>
}>
type Result = Iterate<FlattenedObject>
另一种方法可以更好地处理不同深度的路径(例如 'd.a.c')
type MapNestedKeys<T, P = keyof T> =
P extends `${infer K1}.${infer K2}` & keyof T ?
MapNestedKeys<{[S in K1]: MapNestedKeys<{[S1 in K2]: T[P]}>}> :
P extends string & keyof T ? {[S in P]: T[P]} : {}
我正在尝试将类型表达为一个函数,该函数接受一个带有键的对象作为点分隔路径和 returns 一个新对象,其中所有子路径都被扩展。我无法理解如何在递归 'de-structuring' 它们的同时保留给定路径的原始类型。
// Dummy structure
const flattenedObject = {
'd.a': 1,
'd.b': true,
};
type FlattenedObject = typeof flattenedObject;
// Expected type (or union of sub-paths: `{ d: { a: number } } | { d: { b: boolean } }`)
interface NestedObject {
d: {
a: number;
b: boolean;
}
}
// Attempt
type MapNestedKeys<R, N extends keyof R = keyof R, N0 = N> = N0 extends string
? N0 extends `${infer K1}.${infer K2}`
? { [K in N as `${K1}`]: MapNestedKeys<R, N, K2> }
: { [K in N as N0]: R[K] }
: {};
// Gives union, but types for nested keys are now union on all key types
type Test = MapNestedKeys<FlattenedObject>;
已更新
// Dummy structure
const flattenedObject = {
'a.b.c.d.e': 1,
'f.g.h.j.k': true,
};
type FlattenedObject = typeof flattenedObject;
type Values<T> = T[keyof T]
type MakeObj<Prop, Value> =
Prop extends string ?
Prop extends `${infer Head}.${infer Tail}` ?
{ [Key in Head]: MakeObj<Tail, Value> }
: Prop extends string ? { [K in Prop]: Value }
: never
: never
type Iterate<Obj> = Values<{
[Prop in keyof Obj]: MakeObj<Prop, Obj[Prop]>
}>
type Result = Iterate<FlattenedObject>
另一种方法可以更好地处理不同深度的路径(例如 'd.a.c')
type MapNestedKeys<T, P = keyof T> =
P extends `${infer K1}.${infer K2}` & keyof T ?
MapNestedKeys<{[S in K1]: MapNestedKeys<{[S1 in K2]: T[P]}>}> :
P extends string & keyof T ? {[S in P]: T[P]} : {}