Skip to content

Intersection type in template literal is not reduced to its bare type #57918

Description

@unional

🔎 Search Terms

template literal, intersection type

🕗 Version & Regression Information

⏯ Playground Link

https://www.typescriptlang.org/play?#code/C4TwDgpgBAysBOBLAdgcwCrggHgNJQgA9gJkATAZygoRVQD4oBeKfIk8qmpNKAMigoAZhHhQAqgCgAkAH4oAbVwAaCQF0CxUpUXjVuNTPkBvAL6aOO44oAKg5FAAGAEmO5TjtQC4oAV2QA1sgA9gDuDqZGUADkJAC2YAA2AIYkADKIJPDJidEyPtHcdBlZOXnSBUVo5T7IEABuopKSoJBQAEoAjMywtGiYkNhVDJIA9KNQkwB6si1YHQBMPXA8GFhDfaj8UNbJPt2m9GMT07Nzbe0AzMubAzjRyQBGAMbRR+OTUDPn0O0ALDdVndsA8XtFtrt9lBDsdPt8fh0AKyAujAlzGZC+OKPUQed4nL6zVq-ABsKP663RmOxuMcEKgeygB3xcLOUCAA

💻 Code

typeStringType<Kextendsstring>=Kextendsstring& infer U
? [K,U]extends[U,K]
? {}extends{[Pin `${K}`]: unknown}
? 'templateLiteral'
: 'stringLiteral'
: 'string'
: nevertypeR1=StringType<string>// ^? type R1 = "string"typeR2=StringType<string&{a: 1}>// ^? type R2 = "string"typeR3=StringType<'abc'>// ^? type R3 = "stringLiteral"typeR4=StringType<'abc'&{a: 1}>// ^? type R4 = "templateLiteral" <-- should be "stringLiteral"typeR5=StringType<`${number}`>// ^? type R5 = "templateLiteral"typeR6=StringType<`${number}` &{a: 1}>// ^? type R6 = "templateLiteral"

🙁 Actual behavior

typeR= `${'abc'&{a: 1}}`
// did not reduce => `${'abc' & { a: 1 }}`

🙂 Expected behavior

typeR= `${'abc'&{a: 1}}`
// should reduce to => `${'abc'}`// => `abc`

Additional information about the issue

I mentioned this in #54648 after it is closed. It is limiting our ability to write the types that works with string literal and template literal and there is no alternative way to workaround that.
I'm suggesting this issue should be fixed and restore the behavior in 5.0.

Here is my original comment:

This behavior is causing a few types in type-plus to fail (e.g. IsTemplateLiteral, IsStringLiteral, Omit, IsNegative, etc) unional/type-plus#429.

In term of soundness, IMO it does make sense that ${string & { a: 1 }} to be reduced to ${string}.

in JS, it would be:

constextendedStr=Object.assign('abc',{a: 1})console.log(`${extendedStr}`)// 'abc'

the reasoning being the toString(): string remains unchanged thus the resulting type should be safe to reduce.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions