sindresorhus / type-fest

A collection of essential TypeScript types
Creative Commons Zero v1.0 Universal
13.96k stars 529 forks source link

Issues with `Paths` type #921

Closed matthew-dean closed 4 weeks ago

matthew-dean commented 1 month ago

I'm not sure why this is, but the paths produced by Paths ends up being slightly different from Get. Specifically, it would be nice if Paths produced a string array tuple type like:

[
  'arr[0].field'
  'arr.0.field' // both valid
  // ... other paths
]

... or with a config option, just:

[
  'arr[0].field'
  // ... other paths
]

Instead, it produces only the {dot}{number}{dot} form, like:

[
  'arr.0.field'
  // ... other paths
]

The other problem with Paths is that it can't handle a type extended from Record. For example, imagine this very simple use case:

import get from 'lodash/get'
import type { Paths, Get } from 'type-fest'

export function getter<const T extends Record<string, any>, P extends string = Paths<T>>(
  obj: T,
  path: P
): Get<T, P> {
  return get(obj, path)
}

This produces the TypeScript error:

Type 'Paths<T>' does not satisfy the constraint 'string'.
  Type 'number | `${number}`' is not assignable to type 'string'.
    Type 'number' is not assignable to type 'string'.ts(2344)

Even though we've specified that the record will only have string keys, Paths produces something other than a union of strings.

It looks like a workaround is:

export function getter<const T extends Record<string, any>, P extends string = Exclude<Paths<T>, number>>(
  obj: T,
  path: P
): Get<T, P> {
  return get(obj, path)
}

... but I'm not sure why this should be the case

Upvote & Fund

Fund with Polar

voxpelli commented 1 month ago

Ideally the two would be unified, tracked in https://github.com/sindresorhus/type-fest/issues/863, but I'm not an expert on these types in particular

Emiyaaaaa commented 1 month ago

I perfer add a new option to output the normal result like arr[0].field

And in the feature, this option maybe can choose to output ['arr', '0', 'field'] or arr[0]['field'] or some useful thing.

A question is which should be the default action?

What do you think? @sindresorhus @voxpelli @matthew-dean

sindresorhus commented 1 month ago

We should add an option to use the arr[0].field style.

sindresorhus commented 1 month ago

A question is which should be the default action?

It would be nice if it was compatible with Get by default, but that can be discussed in https://github.com/sindresorhus/type-fest/issues/450