TypeScript Template Literal String Type
Description
TypeScript supports template literal strings[fn:pr], with the same syntax as [JavaScript Template Literals](JavaScript Template Literals). There is also an in progress PR to switch to type alias helpers[fn:aliashelpers].
Syntax
type World = “world”;
type Greeting = hello ${World};
// same as
// type Greeting = “hello world”;
Examples
Unions
With [TypeScript Union Type](TypeScript Union Type) you can mix and match.
type Color = “red” | “blue”;
type Quantity = “one” | “two”;
type SeussFish = ${Quantity | Color} fish;
// same as
// type SeussFish = “one fish” | “two fish”
// | “red fish” | “blue fish”;
type VerticalAlignment = “top” | “middle” | “bottom”;
type HorizontalAlignment = “left” | “center” | “right”;
// Takes
// | “top-left” | “top-center” | “top-right”
// | “middle-left” | “middle-center” | “middle-right”
// | “bottom-left” | “bottom-center” | “bottom-right”
declare function setAlignment(value: ${VerticalAlignment}-${HorizontalAlignment}): void;
setAlignment(“top-left”); // works!
setAlignment(“top-middel”); // error!
setAlignment(“top-pot”); // error! but good doughnuts if you’re ever in Seattle
Objects
type PropEventSource
on(eventName: ${string & keyof T}Changed, callback: () => void): void;
};
/// Create a “watched object” with an ‘on’ method
/// so that you can watch for changes to properties.
declare function makeWatchedObject
let person = makeWatchedObject({
firstName: “Homer”,
age: 42, // give-or-take
location: “Springfield”,
});
// error!
person.on(“firstName”, () => {
});
// error!
person.on(“frstNameChanged”, () => {
});
// success!
person.on(“firstNameChanged”, () => {
console.log(firstName was changed!);
});
Inference
Here we made on into a generic method. When a user calls with the string ‘firstNameChanged’, TypeScript will try to infer the right type for K. To do that, it will match K against the content prior to “Changed” and infer the string “firstName”. Once TypeScript figures that out, the on method can fetch the type of firstName on the original object, which is string in this case. Similarly, when we call with “ageChanged”, it finds the type for the property age which is number).
type PropEventSource
on<K extends string & keyof T>
(eventName: ${K}Changed, callback: (newValue: T[K]) => void ): void;
};
declare function makeWatchedObject
let person = makeWatchedObject({
firstName: “Homer”,
age: 42,
location: “Springfield”,
});
// works! ‘newName’ is typed as ‘string’
person.on(“firstNameChanged”, newName => {
// ‘newName’ has the type of ‘firstName’
console.log(new name is ${newName.toUpperCase()});
});
// works! ‘newAge’ is typed as ‘number’
person.on(“ageChanged”, newAge => {
if (newAge < 0) {
console.log(“warning! negative age”);
}
})
Helpers
Footnotes
[fn:aliashelpers]https://github.com/microsoft/TypeScript/pull/40580
[fn:pr]https://github.com/microsoft/TypeScript/pull/40336