DEV Community

Timothée Clain
Timothée Clain

Posted on

{ES/TS} bit of the day: Typed Tagged Templates

Hi there! Today I'd like to talk about one of my beloved modern javascript features. These are Tagged Templates.

Tagged What?

Basically Tagged Templates are an extension of the basic interpolation mechanism that you normally uses in ES6+.

Using backticks you can elegantly insert values in a string (multiline by the way, :-))

const greet = (name) => `hello ${name}`

greet('timothee') // hello timothee

In one work?

By using the backticks notation with a function identifier, you basically have a template engine for free.

An example please!

Don't worry, it's actually less scary than what it sounds.

Let's take a function like

function myTemplate() {}

We'll see the actual arguments later.

I can call the function with this syntax now.

myTemplate`Hello !`

Weird isn't it?

What's more interesting, is I can actually pass interpolations with the familiar ${} syntax.

Let's try it:

const externValue = "Timothee"
myTemplate`Hello ! ${externValue}`

Of course, I now can use computed values from the surrounding scope of my function call.

This syntax is an actual function call of myTemplate

So what's the magic actually?

Let's see the arguments passed to the function:

  • The first argument is a list of invariant strings
  • the n others arguments are all the other interpolation produced by ${} usage.

For instance, if I make this call:

myTemplate`Hello,${"Timothee"},World`

The first argument will be a list of all strings that don't change inside the passed string:

["Hello,", ",World"]

Of course, if you don't use any interpolations, you will have one element inside this array, the entire passed string.

The next argument will be my first interpolation, here it's a constant string: Timothee.

So if we have n interpolation in our template string, we all have n+1 elements in our first array, and n more arguments passed to the function.

Cool, but how is it useful?

Whenever you need to apply transformations to a string with interpolation (aka dynamic values), this can be very useful.

For instance, you could build a template engine respecting the native semantics of es6

html`<h1>Hello ${name}</h1>`;

Actually, this already exists: https://lit-html.polymer-project.org/

In the react context, this technique is used to generate pre-styled components from CSS code for CSS-in-js solutions as emotion or styled-components.

const PrestyledComponent = styled('div')`
/** real css here */
background-color: blue;
`

// usage
const Fragment = <PrestyledComponent />

How can we type tagged templates

In typescript, we can add type information to our tagged templates:

function tagged(strings: TemplateStringsArray, ...args: boolean[]){
  console.log(args)
}

The idea is to type the first argument as the TemplateStringsArray type and the subsequent interpolations to whatever you need.

Let's take an example. Let's say you want to have auto-completable access to your theme from a styled component

export const theme = {
  'colors.hello': true
}

export type ThemeKeys =  keyof typeof theme


function themedStyled(strings: TemplateStringsArray, ...args: ThemeKeys[]){
  console.log(args)
}


themedStyled`
  background-color: ${};
`

And you got auto-completion of your theme keys for free!

Autocompletion

That's it for today. Till next time!

Latest comments (0)