What are Template Literal Types?

Justin Lee
3 min readAug 8, 2021

After TypeScript 4.1 came out, we now can use the “Template Literal Type”. There are so many awesome features in it. In this article, I will highlight some features, but it is very recommended to read the official docs.

Template Literal Type?

It is making a new type from the string literal type of TypeScript.

  • Basic
type Justin = 'justin';type JustinLee = '${Justin} Lee';

We now can combine string and type to make a new type.

  • Union Type
type Banana = 'banana';
type Toppings = 'chocalate' | 'strawberries' | 'blueberries' | 'syrup';
//type BananaToppings = 'banana chocolate' | 'banana strawberries' | 'banana blueberries' | 'banana syrup';
type BananaToppings = `${Banana} ${Toppings}`;

You can simply link types, you can extend your type to various ways.

  • Union Types
type VerticalAlignment = "top" | "middle" | "bottom";
type HorizontalAlignment = "left" | "center" | "right";
// type Alignments =
// | "top-left" | "top-center" | "top-right"
// | "middle-left" | "middle-center" | "middle-right"
// | "bottom-left" | "bottom-center" | "bottom-right"
type Alignments = `${VerticalAlignment}-${HorizontalAlignment}`;
  • Key Remapping in Mapped Types
type Options = {
[K in "isLoading" | "hasElements" | "isActive"]?: boolean;
};
// same as
// type Options = {
// isLoading?: boolean,
// hasElements?: boolean,
// isActive?: boolean
// };
  • Capitalize<type>
type Get<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};
interface User {
name: string;
age: number;
location: string;
}
type CapitalizedUser = Get<User>;
// type CapitalizedUser = {
// getName: () => string;
// getAge: () => number;
// getLocation: () => string;
//}
  • Interfacing type
//Simple literal typestype InOrOut<T> = T extends `fade${infer R}` ? R : never;//type I = "In"
type I = InOrOut<"fadeIn">;
//type O = "Out"
type O = InOrOut<"fadeOut">;

//Split literal with '.'
type Split<S extends string> =
S extends `${infer T}.${infer U}` ? [T, ...Split<U>] : [S];
// type S = ["foo", "bar", "baz"];
type S = Split<"foo.bar.baz">;
  • ValueOf (it’s not from 4.1 but just to keep in mind)
interface Foo {
foo: {
bar: {
baz: string;
}
}
}
//type A = { bar: { baz: string} };
type A = ValueOf<Foo, ['foo']>;
//type B = { baz : string };
type B = ValueOf<Foo, ['foo', 'bar']>;
//type C = string;
type C = ValueOf<Foo, ['foo', 'bar', 'baz']>;

Ex1) Make JSON parser with TypeScript

// type Json = { key1: ['value1', null]; key2: 'value2' }; 
type Json = ParseJson<'{ "key1": ["value1", null], "key2": "value2" }'>;

As you can see you can just insert your JSON to ParseJson type.

Ex2) Make snake_case type to camelCase type

type CamelizeString<T extends PropertyKey> = 
T extends string ? string extends T ? string :
T extends `${infer F}_${infer R}` ? `${F}${Capitalize<CamelizeString<R>>}` : T : T;

type Camelize<T> = { [K in keyof T as CamelizeString<K>]: T[K] }

type CamelizeExample = Camelize<Example>;
/* type CamelizeExample = {
firstName: string;
lastName: string;
homeTown: string;
} */

const e: Camelize<Example> = {
firstName: 'string',
lastName: 'string',
homeTown: 'string'
}

Awesome, Right?

References

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Justin Lee
Justin Lee

Written by Justin Lee

Software Engineer at Loblaw Digital

No responses yet

Write a response