Improve comparable relation of template literal types to detect more impossible situations #57872
Description
🔎 Search Terms
string condition always return false
2367 template
🕗 Version & Regression Information
This is the behavior in every version after 4.4.4 (including nightly), and I reviewed the FAQ for entries about "template" or "string"
This issue claims to fix a related problem in 4.5, but 4.5.5 is the first issue that fails for me. Maybe no relation though.
#45201
In 4.4.4 it it fails correctly though, so maybe that fix is the regression of this issue?! https://www.typescriptlang.org/play?ts=4.4.4#code/C4TwDgpgBAglC8UAGBDAXGgJAbwHYFcBbAIwgCcBfJAKFEigCEFliMcCTyrrbxoANZkgAebPEVKUadaAE0h7CVxrUAxgHtcAZ2BR0sIeizYAjNw3bdrRkNbGzKizqiiogxCLEO1m5yDRQ8h443tQAlgBmUAAUwgjwiCAAlFDY1FBQTuoANhAAdNnqAObRAOTAABZhWlBaFer42QAmUBUoAG7QEShhuU2lSdQUPJExKPGIxClpGVm5BcVl3b01GmRkEKrA2SADQ9RAA
⏯ Playground Link
💻 Code
type A = `a::${number}`
type B = `b::${number}`
type X = `x::${number}`
type Y = `${number}`
const a: A = `a::${1}`
const b: B = `b::${1}`
const x: X = `x::${1}`
const y: Y = `${1}`
if (x === y) {
console.log('this should have failed')
}
if (a === b) {
console.log('fails correctly')
}🙁 Actual behavior
Comparing x and y generates no complaints from TS for "x::1" and "1", but does for "a::1" and "b::1". There is no way for a number to evaluate to "x:: so there is no overlap between these template types.
🙂 Expected behavior
I would expect that Typescript shows that error consistently whenever types don't match.
There is no overlap between a string that must start with "x::" and one that must start with a number.
Additional information about the issue
No response
Activity
RyanCavanaugh commentedon Mar 22, 2024
Bisects to #46137
RyanCavanaugh commentedon Mar 22, 2024
That PR adds this code
where
templateLiteralTypesDefinitelyUnrelatedis currently conservatively defined as:I'm not sure how much further we want to take this logic; allowing more things than is technically possible in the comparable relation isn't a very big defect, and it's somewhat hard to put exact bounds on what the
toStringof any number might be -- if we tighten up to say the first digit must be numeric or something, then there's still a "bug" where sequences like"00"aren't detected as being not-possible outputs oftoString.[-]Template types involving `number` don't fail when compared without overlap (`x::${number}` versus `${number}`) 2367[/-][+]Improve comparable relation of template literal types to detect more impossible situations[/+]hitsthings commentedon Mar 23, 2024
Is this area very performance-bound? I've been hashing it out and I think I could write something to relatively accurately compare two template strings for overlap, but it'd necessarily require checking a lot of different options. It would presumably take a lot more time than checking if the first and last parts are the same.
Is it worth the time for me to explore that?
This caused me to ship a bug so I'd like to fix it. Otherwise I have to use branded strings to distinguish my number strings from other strings which is kinda annoying.
RyanCavanaugh commentedon Mar 25, 2024
Overall codesize and complexity is a budget we have to manage. By far the most common complaint we get in this area is that "I should be able to compare anything"; we get very few "I was not allowed to compare two things that in reality didn't overlap". So I'd really need to see more feedback from other people on this before committing to consider any approach.
hitsthings commentedon Mar 25, 2024
Ok fair enough. Thanks for the explanation!