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
Enter fullscreen mode Exit fullscreen mode

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() {}
Enter fullscreen mode Exit fullscreen mode

We'll see the actual arguments later.

I can call the function with this syntax now.

myTemplate`Hello !`
Enter fullscreen mode Exit fullscreen mode

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}`
Enter fullscreen mode Exit fullscreen mode

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`
Enter fullscreen mode Exit fullscreen mode

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

["Hello,", ",World"]
Enter fullscreen mode Exit fullscreen mode

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>`;
Enter fullscreen mode Exit fullscreen mode

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 />

Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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: ${};
`
Enter fullscreen mode Exit fullscreen mode

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

Autocompletion

That's it for today. Till next time!

Top comments (0)