DEV Community

Cover image for Create object property string path generator with typescript
Volodymyr Yepishev
Volodymyr Yepishev

Posted on

Create object property string path generator with typescript

Create object property string path generator with typescript

Wow, that was a large noun cluster. Well, what is it anyway?

Now, using some libraries/frameworks you might sometimes need to generate a string that would represent a path to a property of some object, for example when you need to perform a get on Angular's FormGroup or have nested form field in React Hook Form.

You could create several monstrous constants, ie something akin to:

const nestedAddressField = 'user.contacts.address';
Enter fullscreen mode Exit fullscreen mode

Or maybe use template strings and enums, but there is a better way.

Typescript 4 bring along amazing stuff: Template Literal Types
. These are the solution.

Now, using this amazing feature we can create a type with infinite recursion and a helper function to generate all possible property paths an object has for us.

Check this out. First let us create a type that would basically be a colletion of all possible string paths in an object:

// For convenience
type Primitive = string | number | bigint | boolean | undefined | symbol;

// To infinity and beyond >:D
export type PropertyStringPath<T, Prefix=''> = {
    [K in keyof T]: T[K] extends Primitive | Array<any> 
    ? `${string & Prefix}${ string & K }` 
    : `${string & Prefix}${ string & K }` | PropertyStringPath <T[K], `${ string & Prefix }${ string & K }.`> ;
}[keyof T];
Enter fullscreen mode Exit fullscreen mode

Basically what it does is iterating over object's properties and returning each field as a string with a given prefix. Initially the prefix is empty string, which is nothing. If it encounters a primitive or an array, it returns a string with prefix, if it encounters an object, it then invokes itself recursively, but adds a dot to the prefix. Easy-peasy.

Now what's left to do is to create a simple factory that can generate us helper functions to provide hints:

export function propertyStringPathFactory<T, R=string>(): (path: PropertyStringPath<T>) => R {
    return (path: PropertyStringPath<T>) => (path as unknown as R);
Enter fullscreen mode Exit fullscreen mode

So now instead of walking on eggshells with strings we can use helper function that safeguards us from making mistakes.

Have fun ^_^

Oh, and by the way, there's an npm package with this utility 💪


Discussion (5)

bregy1 profile image
bregy1 • Edited on

The code works indeed but should not be used because of infinite recursion. The Compiler will heavily be used and your IDE will be working way less fast. Just so others know. For having a recursion limiting approach checkout "Paths" type of this stackoverflow answer:

bwca profile image
Volodymyr Yepishev Author • Edited on

Unfortunately, in practice you can't get infinite recursion, it appears there is some sort of a hidden safeguard against it.

I actually tried to kill the playground page by deliberately applying type helper to a self referencing interface and trying to get hints, which was supposed to give me infinite amount of them and hang everything, but it just doesn't work that way. I wonder what are the checks under the hood that guard against it.

UPT: oh, yeah, there's a safeguard in ts if (instantiationDepth === 50 || instantiationCount >= 5000000) :D

bregy1 profile image

Okay. Well I wrote the comment cuz vscode complained about the error and it was way slower than usual with type checking..

Anyways, nice post and answer : )

goququ profile image
qu • Edited on

Hi i've tried to use your code, but there is an error.

bwca profile image
Volodymyr Yepishev Author

Might it be that the version of typescript you are trying to use it with is under version 4? Template Literal Types are not available in versions below 4.

You can check it in the playground: once you choose version under 4, you start getting errors