Description
Template String Types for Template Expressions
(continued)
-
Strong feelings on this?
- Seems better, and more consistent, with templates with no holes.
- As soon as you added holes in positions, then you lose it.
- So part of the idea is we're trying to faithfully reflect what's happening in the type system.
-
+
concatenations don't do this though - that's very inconsistent. -
If we were to introduce
+
for anyT
andU
. -
We don't support algebraic operators in general.
const a: 42 = 42; const b: 3 = 3; const c = a + b
-
In DefinitelyTyped, we recently had a PR with a huge number of strings - one could argue that's strictly better.
- This was a template type - not a template literal.
- feat(terra-spacer): Add type defs for terra-spacer DefinitelyTyped/DefinitelyTyped#50748
-
Should a new programmer have to see this behavior?
-
New programmer will usually see a union type.
- Will sometimes see a template with an interpolated
string
though!
- Will sometimes see a template with an interpolated
-
There's a widening/non-widening form, right?
-
Yes
-
But we don't always do literal widening for functions!
-
Simplified
declare var srcSvgData: SvgData[]; interface SvgData { fileName: string; iconName: string; } const c = srcSvgData.map( (svgData) => `<a href="./svg/${svgData.fileName}"><svg><use href="#${svgData.iconName}" xlink:href="#${svgData.iconName}"/></svg></a>`, );
-
Could argue the problem is that we don't look at the whole program.
-
-
Consistency arguments don't exactly feel useful because you want the literal type so you can compare for literal unions.
- When you have an infinite set...that feels somewhat less useful.
- Consistency vs. usability argument, usability feels more compelling to me.
-
Could imagine "only create a literal type if it's finite"
- Still hard to explain "if you fill your hole with a string, you won't get a literal-ish type."
-
Maybe the most minimal change is to make return statements do different widening.
-
Can always opt in with
as const
with old behavior. -
There is some sentiment that the behavior is good; but should just make concessions to widening on function returns.
// This should probably keep working like it does post-PR: let a = 12; const lit = `${a}px`; usePxValue(lit); const obj = { lit };
-
But feels strange, that if you wrote this as
makePx
, and we widened for you, that'd be bad. -
unique symbol
s widen to symbols. -
Seems like these should work the same.
let a = 12; const c = `${x}px`; function makePxValue1(x: number) { return `${x}px`; } function makePxValue2(x: number) { const c = `${x}px`; return c; }
-
If we revert, we can avoid all these contextual rules.
- Only time we infer literal types is if they're finite.
- Also, can maintain the
string
slots when contextually typed.
-
Seems like reverting is a reasonable option, so you'd just end up with
string
unless you writeas const
- same way with arrays/object literals. -
What kind of inferences would we need to make this better? Seems like these are desirable.
- Well you have to speculate with these super-specific types - that's why we have widening. So you don't really know.
- We need to see where/when/how types are mutated.