Exploring JavaScript Tagged Template Strings

Raymond Sohn

@20percentempty

Prologue

What Are Template Strings?

Before

var value = 'Regular String';

console.log('Hello ' + value + '!');
'Hello Regular String!'

After

var value = 'Template String';

console.log(`Hello ${value}!`);
'Hello Template String!'

1

What Are Tagged Template Strings?

GraphQL Tag

var query = gql`{
  users {
    name
  }
}`
{
  kind: 'Document',
  definitions: [
    {
      kind: 'OperationDefinition',
      operation: 'query',
      selectionSet: […],

    }
  ]
}

2

How Do Tagged Template Strings Work?

Arguments Tag

function args(strings, ...values) {
  return { strings, values };
}

var value = 'Arguments';

args`Hello ${value}!`
{
  strings: ['Hello', '!'],
  values: ['Arguments']
}

NO-OP Tag

function noop(strings, ...values) {
  var result = '';
  // Append each string to the result.
  strings.forEach((string, index) => {
    result += string;
    // If a value exists then append it to the result.
    if (index < values.length) {
      result += values[index];
    }
  });
  return result;
}

var value = 'No Operation';

noop`Hello ${value}!`
'Hello No Operation!'

3

What Else Can We Do
With Tagged Template Strings?

Embed Domain Specific Languages

  • Build single file web components with embedded HTML and CSS.
  • Port Bash’s backticks syntax to execute shell commands.

Metaprogramming

  • Inspect Abstract Syntax Trees to improve our understanding of the JavaScript language.

Async Programming

  • Promise-aware template strings.

Quantum Computing

  • Simulate quantum circuits.

Single File Web Components with LitElement

import { LitElement, css, html } from 'lit-element';

class HelloComponent extends LitElement {
  static get styles() {
    return css`p { font-weight: bold }`;
  }

  render() {
    return html`<p>Hello Component!</p>`;
  }
}

customElements.define('hello-component', HelloComponent);
<hello-component></hello-component>

Shell Tag

var shell = require('shelljs');

function sh(strings, ...values) {

  return shell.exec(result, { silent: true });
}

sh`echo 'Hello Shell!'`
{
  stdout: 'Hello Shell!\n',
  stderr: '',
  code: 0,

}

Abstract Syntax Tree Tag

var template = require('@babel/template');

function ast(strings, ...values) {

  return template.smart.ast(result);
}

ast`1 + 2 * 3`

{
  type: 'ExpressionStatement',
  expression: {
    type: 'BinaryExpression',
    operator: '+',
    left: { type: 'NumericLiteral', value: 1 },
    right: {
      type: 'BinaryExpression',
      operator: '*',
      left: { type: 'NumericLiteral', value: 2 },
      right: { type: 'NumericLiteral', value: 3 }
    }
  }
}

Multiplication precedes addition.

1 + (2 * 3)

Promise Tag

// A promise that waits 5 seconds and
// then returns the string 'Promise'
var promise = new Promise(resolve =>
  setTimeout(() => resolve('Promise'), 5000)
);

p`Hello ${promise}!`.then(console.log);

5 seconds after being called…

'Hello Promise!'

function p(strings, ...promises) {
  // Return a promise for the caller to wait on.
  return new Promise((resolve, reject) => {
    // Wait for all of the promises to resolve.
    Promise.all(promises).then(values => {
      var result = '';
      strings.forEach((string, index) => {
// Concatenate the template string.
      });
      // Resolve the promise with the result.
      resolve(result);
    }, reject);
  });
}

Simulating Quantum Circuits with Q.js

Q`
  H  X#0
  I  X#1
`

quantumjavascript.app/playground.html

Epilogue

Thank you for your time. You can find more examples, the slides and the transcript for this talk at git.io/JvSGK.