ts-toolbelt
ts-toolbelt copied to clipboard
Object.Paths broken with TS 4.9
🐞 Bug Report
Describe the bug
Object.Paths doesn't seem to be working right with 4.9. Not sure where the bug is
Reproduce the bug
https://www.typescriptlang.org/play?ts=4.9.0-dev.20221011#code/JYWwDg9gTgLgBAbzgeQEYCsCmBjeBfOAMyghDgHIYBnAWhgggBtVNGZyBuAKC5gE8wmOGACGMABZU4AXhQYcMAHQAFMZIA8Sca0YQAXHCowowAHYBzOHgB8HIA
paths
is of type readonly Key[]
in 4.9
Expected behavior
The same snippet running in 4.8
https://www.typescriptlang.org/play?ts=4.8.4&ssl=3&ssc=46&pln=3&pc=44#code/JYWwDg9gTgLgBAbzgeQEYCsCmBjeBfOAMyghDgHIYBnAWhgggBtVNGZyBuAKC5gE8wmOGACGMABZU4AXhQYcMAHQAFMZIA8Sca0YQAXHCowowAHYBzOHgB8HIA
Possible Solution
Screenshots
Additional context
Same issue here, anyone has any idea how to sort that out? It seems the lib is abandoned =/
I just wrote my own version to replace it. Probably going to be doing that for the rest of my ts-toolbelt usages too
I'm having that same issue here, TypeScript 4.8 works just fine!
Same issue here, anyone has any idea how to sort that out? It seems the lib is abandoned =/
Damn, ran into the same issue on my end @bissolli :D very sad.
Same issue here, anyone has any idea how to sort that out? It seems the lib is abandoned =/
Damn, ran into the same issue on my end @bissolli :D very sad.
As we were not using the lib extensively we ended up removing the lib as it seems to be abandoned! Hope you find a solution on your end man ;)
This ObjectPaths type is the code I used to replace ts-toolbelt's Object.Paths
post-TS 4.9. It's probably not perfect in terms of weird edge cases, but works for what I need from it. It handles unions, circular types, and array paths.
type DistributedKeyof<Target> = Target extends any ? keyof Target : never;
type DistributedAccess<Target, Key> =
Target extends any
? Key extends keyof Target
? Target[Key]
: undefined
: never;
type Leaf =
| Date
| boolean
| string
| number
| symbol
| bigint;
type DepthCounter = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
type ObjectPaths<
Target,
Depth extends DepthCounter[number] = 10
> = Depth extends never
? never
: Target extends never
? never
: Target extends Leaf
? never
: {
[Key in string & DistributedKeyof<Target>]: [Key] | (
NonNullable<DistributedAccess<Target, Key>> extends (infer ArrayItem)[]
? | [Key, number]
| (ObjectPaths<ArrayItem, DepthCounter[Depth]> extends infer V extends any[]
? [Key, number, ...V]
: never
)
: (
ObjectPaths<NonNullable<DistributedAccess<Target, Key>>, DepthCounter[Depth]> extends infer V extends any[]
? [Key, ...V]
: never
)
)
}[string & DistributedKeyof<Target>];
// ----------
type SomeType = {
name: string;
nested: {
value: number;
}[]
}
type p = ObjectPaths<SomeType>;
// ^?
I actually found this code online somewhere, does the same thing...
export type NestedKeyPaths<ObjectType extends object> = {
[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object
? `${Key}.${NestedKeyPaths<ObjectType[Key]>}`
: `${Key}`;
}[keyof ObjectType & (string | number)];
👍 That code is similar to mine, but doesn't handle unions or circular types