Restrict template literal interpolation expressions to strings
See original GitHub issueSearch Terms
“template literal”
There are many hits, some which seem related, but everything I could find was a much bigger ask or wider in scope
Suggestion
Add a compiler option to enforce using only strings in ES6 string template literals
Use Cases
When using string literals, any variables are coerced to strings, which can lead to undesirable behavior.
As far as I can tell there’s no way to avoid this behaviour. In the spirit of tying everything, I’d prefer that only actual string
types are permissible for use in string templates to avoid accidental coercion by passing null, undefined or object types that may have unexpected string representations, and force users to explicitly convert them to strings.
Examples
For example:
function formatName(name: string | null): string {
return `Name is: ${name}`;
}
formatName(null) === "Name is: null"
Ideally the compiler would fail since name
can be null.
Checklist
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.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:51
- Comments:36 (3 by maintainers)
Top GitHub Comments
This is a contrived example; obviously I wouldn’t write a function like this. In real work, we deal with complex data structures that have many fields of differing types. We process data that is far removed from its type definitions. That’s the whole point of static typing.
I wouldn’t write a function so narrowly purposed that allowed
null
, of course, but I might have a React component that takes a lot of props, some of which can be null or are optional, but I will still eventually use string templates to format data involving those fields. Unless I wrapped every single usage of a string template literal in a function that took astring
arg for every field, I would face this risk.The point of type safety is to protect you from mistakes. If people always correctly grokked the type of every variable they used in practice, then we wouldn’t need typescript at all. But people don’t. I might have a structure:
If I did this:
I get
“Joe undefined Blow lives at [Object object]”
This would be a very easy mistake to make.
Personally, there’s never a time when I want type coercion. I don’t see why this is a place you’d want it, any more than you’d want it when assigning anything else to a variable of type
string
. String literal templates only deal with strings; it seems well within the purpose of TypeScript to enforce that we can only pass them strings.BTW, the use case that this came up had to do with refactoring. I had to take an existing type and change it from
string
tostring | null
. If string template literal types were typesafe, the compiler would immediately fail in every place it was used in a string literal, as it currently would fail everywhere else it was no longer safe to use. Without the ability to type string template literals, you can’t ever safely refactor code involving them when widening types.typescript-eslint has a
restrict-template-expressions
rule to catch this