millsp / ts-toolbelt

👷 TypeScript's largest type utility library

Home Page:https://millsp.github.io/ts-toolbelt/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Object.Paths broken with TS 4.9

bsssshhhhhhh opened this issue · comments

🐞 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.

TS Playground Link

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