Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Allow Type Checking to be Extended (into Tagged Templates, for example)

See original GitHub issue

Search Terms

Tagged Templates, template literals, JSX, htm, lit, lit-html, hyperhtml, nanohtml, choo


Many developers are exploring Tagged Templates as an alternative to JSX/TSX, as the result offers some important advantages. In particular, Tagged Templates parse faster than compiled JSX in all modern JS engines [1], and expose potential optimizations for consuming rendering libraries to be able to bypass comparison logic for identified static portions of a UI representation.

Regardless of the merit of these advantages, one of the key drawbacks cited by developers when adopting Tagged Templates in place of TSX is the lack of typing within static templates and associated expression parts. This affects all libraries using Tagged Templates.

[1]: analysis and benchmark data forthcoming, email me for access if necessary.

Using htm as an example:

interface Props {
    sticky: boolean;
function Header({ sticky }: Props) {
  return html`<header class=${'header' + (sticky ? ' sticky' : '')} />`;
render(html`<${Header} sticky=${'yes'} />`);
// Incorrect type, but no error ^^^^^

(view example in playground)

Since the template’s static parts are an unknown format, this is logical. However, consider the compiled output of the above:

interface Props {
    sticky: boolean;
function Header({ sticky }: Props) {
  return h('header', {class: 'header' + (sticky ? ' sticky' : '')});
render(h(Header, { sticky: 'yes' }));
//                 ^^^^^^
//                 Type 'string' is not assignable to type 'boolean'.

(view example in playground)

I would like to suggest that we need a solution for type-checking Tagged Templates. The shortest-path solution would be to special-case checking for Tagged Templates with a tag function that has a local identifier with the name html, though clearly that’s not optimal as implementation of html can vary.

Use Cases

The use-case for this is to allow developers to express view hierarchies in standard JavaScript syntax rather than JSX/TSX, while preserving the typing support currently offered by TSX being integrated into TypeScript’s parser.

If a design were to be proposed to extend type checking to arbitrary opaque Tagged Templates (perhaps through plugins), this would allow a whole host of untyped code to be checked by the TypeScript Compiler. I’m fairly certain the various CSS-in-JS solutions would be also interested in this level of static analysis in order to errors currently handled at runtime into compilation.


interface Props {
    sticky: boolean;
function Header({ sticky }: Props) {
  return html`<header class=${'header' + (sticky ? ' sticky' : '')} />`;
render(html`<${Header} sticky=${'yes'} />`);
//                            ^^^^^^^^
//                            Type 'string' is not assignable to type 'boolean'.


My suggestion meets these guidelines:

  • This wouldn’t be a breaking change in existing TypeScript/JavaScript code
  • This wouldn’t change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn’t a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript’s Design Goals. (specifically goals 1, 2 & 6)

/cc @IgorMinar @JustinFagnani @RobWormald @Surma

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:33
  • Comments:21 (7 by maintainers)

github_iconTop GitHub Comments

trusktrcommented, Oct 20, 2020

At least we have a partial built-in solution now:

For example, using the new Template String Types, then in

const div = html`<div>...</div>`
const p = html`<p>...</p>`

the type of div will be inferred to HTMLDivElement, and p will be HTMLParagraphElement.

playground example

justinfagnanicommented, Jan 16, 2019

cc @octref and @rictic

In our experience looking into this, one of the first missing pieces is a type construction API. We can parse a template, like:

html`<my-element .prop=${}`></my-element>

And know how we should build the type of the LHS of the implied assignment, ie:

typeof HTMLElementTagNameMap['my-element'].prop

but we don’t have an actual API to build the type. If we did, there is an API for checking assignability.

Once we have those pieces we can do this in a compiler plugin. From there we would really love to have a way to specify plugins in tsconfig so we don’t have to write a wrapper around tsc.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Template literals (Template strings) - JavaScript | MDN
Tags allow you to parse template literals with a function. The first argument of a tag function contains an array of string values....
Read more >
Magic of Tagged Templates Literals in JavaScript? - Hemil Patel
Tagged template literals let you extract all the dynamic values, which are called tags, and segregate them from the static content. This gives ......
Read more >
8. Template literals - Exploring JS
Tagged template literals allow you to implement custom embedded sub-languages (which are sometimes called domain-specific languages) with little effort, because ...
Read more >
Template Literals and a Practical Use of Tagged Templates in ...
They are String literals that allow you to do the following things that you cannot do with normal strings. ... Let's see these...
Read more >
Binding to Tagged template function - ReScript Forum
The more difficult parts will be figuring out how to express tagged templates within the parse tree in such a way that they'll...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Post

No results found

github_iconTop Related Hashnode Post

No results found