type-fest
type-fest copied to clipboard
Suggestion: deep version of StringKeyOf
Hey,
It could be great to have a deep version of the utility type StringKeyOf that would extracts nested keys with dot-notation. Pretty useful when working with libraries using dot-notation to access values or to manipulate types.
Example
interface Foo {
a: string;
b: number;
c: {
nestedA: string;
}
}
type Bar = StringKeyOfDeep<Foo>;
// ^? 'a' | 'b' | 'c' | 'c.nestedA'
Pretty useful when working with libraries using dot-notation to access values or to manipulate types.
How is a union of all key paths useful for this?
We already have a Get
type to deal with key paths (dot-notation), and soon also a SetProp
type: https://github.com/sindresorhus/type-fest/pull/409
Hey,
Get
type does not return a union of all possible key paths.
A simple example :
I have a generic type with a prop (key
here) representing an accessor in the provided type T
(a key path)
interface ColumnDefinition<T> {
id: string;
label: string;
key: StringKeyOf<T> // or keyof T
}
I have an interface representing my object, with nested properties
interface MyObject {
_id: string;
name: string;
customData: {
type: string;
enabled: boolean;
};
}
Then, when using my generic type
type MyObjectColumnDefinition = ColumnDefinition<MyObject>;
// here, key will be : '_id' | 'name' | 'customData'
// with a deep version it could have been : '_id' | 'name' | 'customData' | 'customData.type' | 'customData.type.enabled' adding deepProperties to union
I don't think the Get
type you reference would allow it.
Additionally, it would be nice to have features like the Path type in React Hook Form. 🙏
It also supports arrays. (It may deviate from StringKeyOfDeep, but...)
type Post = {
id: string;
title: string;
comments: {
id: string;
body: string;
}[]
}
type fieldType = Path<Post>;
// type fieldType = "id" | "title" | "comments" | `comments.${number}` | `comments.${number}.id` | `comments.${number}.body`
Thanks for maintaining a great library!
A leaves-only version of this would also be really useful:
type Post = {
id: string;
title: string;
comments: {
id: string;
body: string;
}[]
}
type fieldType = Path<Post, { onlyLeaves: true }>;
// type fieldType = "id" | "title" | `comments.${number}.id` | `comments.${number}.body`
I was hoping StringKeyOf
was deeply nested but sad it wasnt.
However, another library I am using, react-hook-form, has a similar concept util type call Path
:
/**
* Helper type for recursively constructing paths through a type.
* See {@link Path}
*/
declare type PathImpl<K extends string | number, V> = V extends Primitive | BrowserNativeObject ? `${K}` : `${K}` | `${K}.${Path<V>}`;
/**
* Type which eagerly collects all paths through a type
* @typeParam T - type which should be introspected
* @example
* ```
* Path<{foo: {bar: string}}> = 'foo' | 'foo.bar'
* ```
*/
export declare type Path<T> = T extends ReadonlyArray<infer V> ? IsTuple<T> extends true ? {
[K in TupleKeys<T>]-?: PathImpl<K & string, T[K]>;
}[TupleKeys<T>] : PathImpl<ArrayKey, V> : {
[K in keyof T]-?: PathImpl<K & string, T[K]>;
}[keyof T];
Duplicate of #213
This is accepted. The type should be named Paths
.
I agree it should include a onlyLeaves: true
option as mentioned in https://github.com/sindresorhus/type-fest/issues/432#issuecomment-1219428546.
See the initial attempt at adding this here: https://github.com/sindresorhus/type-fest/pull/300
Don't forget to add StringKeyOfDeep
as an alternative name here: https://github.com/sindresorhus/type-fest#alternative-type-names
Relevant Stack Overflow answer: https://stackoverflow.com/questions/58434389/typescript-deep-keyof-of-a-nested-object
Also some inspiration in https://github.com/sindresorhus/type-fest/issues/213
I think this was completed in https://github.com/sindresorhus/type-fest/pull/741
@voxpelli i think one thing still open is a "leaves only" option, see https://github.com/sindresorhus/type-fest/issues/432#issuecomment-1321117787
@stefanprobst Lets keep track of that in #860, easier to pinpoint then. Does that sound good?
Lets keep track of that in https://github.com/sindresorhus/type-fest/issues/860, easier to pinpoint then. Does that sound good?
perfect, thanks!