-
Notifications
You must be signed in to change notification settings - Fork 13k
Open
Labels
Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScriptAn idea for TypeScript
Description
π Search Terms
template literal, intersection type
π Version & Regression Information
- This changed between versions 5.0 and 5.1
- This changed in commit or PR Template string type infers error when string intersect with object typeΒ #48034 Performance regression from #48044Β #52345 5.1.3 new "feature"? Branded types are preserved in
const
template literalΒ #54648
β― Playground Link
π» Code
type StringType<K extends string> = K extends string & infer U
? [K, U] extends [U, K]
? {} extends { [P in `${K}`]: unknown }
? 'templateLiteral'
: 'stringLiteral'
: 'string'
: never
type R1 = StringType<string>
// ^? type R1 = "string"
type R2 = StringType<string & { a: 1 }>
// ^? type R2 = "string"
type R3 = StringType<'abc'>
// ^? type R3 = "stringLiteral"
type R4 = StringType<'abc' & { a: 1 }>
// ^? type R4 = "templateLiteral" <-- should be "stringLiteral"
type R5 = StringType<`${number}`>
// ^? type R5 = "templateLiteral"
type R6 = StringType<`${number}` & { a: 1 }>
// ^? type R6 = "templateLiteral"
π Actual behavior
type R = `${'abc' & { a: 1 }}`
// did not reduce => `${'abc' & { a: 1 }}`
π Expected behavior
type R = `${'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:
const extendedStr = 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
Labels
Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScriptAn idea for TypeScript