Image for post
Image for post

Less Redux Boilerplate Using Typescript Template Literals

Mikhail Boutylin
Jan 21 · 3 min read

Typescript 4.1 introduced an incredibly powerful feature called Template Literal Types. It allows developers to write better typing for strings, so typescript can check them to match certain template:

In the example above a variable of type Percent can accept a string value, that starts with a numeric string and terminates with % .

Another, even (in my opinion) more important use case is possibility to map keys of an object.

Let get a step back to explain what happens in detail. Suppose Getters would have the following definition:

K in keyof T means that interface transformed with Getters will have same keys as initial one. () => T[K] means that values corresponding to those keys will be functions that return T[K]. And T[K] is the original type of value corresponding to the key K. This will return an interface like:

However it’s not a conventional naming for get functions. Prior to TS 4.1 there was no way to solve this issue (other than explicitly mapping each key in the code). But now with addition of Template Literal Types we can transform keys in a reusable way. To transform a key you need to use as operator which on the left has selection of keys and transformation of keys on the right.

Now let analyze `get${Capitalize<string & K>}`. A key (e.g. name) gets capitalized (will become Name) and prepended by get. And since a key of object can benumber | string | symbol, we need to enforce that keys of object passed to Getters has string keys string & K. If command `get${Capitalize<string & K>}` is still unclear, take a look at the diagram bellow.

Image for post
Image for post

Ok, but how it’s related to redux ? :)

To write performant application with React we need a way to re-render components only when this is needed. For this purpose we should only select from store only information needed to display actual state. Let suppose we have following state shape for active user in a video game:

If your component selects full activePlayer object, it will cause re-renderings even in case this is not needed (e.g. gold field is updated, but it’s not rendered in the component).

One way to avoid those re-renderings, is to create a selector for each field we need to render individually:

Looks terrible?

A logical question here would be, if we can write an utility that could create those selectors for us by just accepting selectActiveUser (used as a base selector), and the default activeUser state (so the utility will know what keys does this object have); Let call it selectorify.

And in reality it turns out a pretty easy thing to do. We just need to map keys and values of default state. For example key name should become selectName and the corresponding value, should be a selector which will return property name of active user. For simplicity, let take a look to version without ts:

And this is version of ts declaration (from a .d.ts) file:

Now you can create 100% typed selectors for each key of your feature.

P.S.

The Startup

Medium's largest active publication, followed by +771K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store