@@ -17696,7 +17696,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
17696
17696
17697
17697
function addSpans(texts: readonly string[], types: readonly Type[]): boolean {
17698
17698
for (let i = 0; i < types.length; i++) {
17699
- const t = types[i];
17699
+ const t = stripObjectTypeTags( types[i]) ;
17700
17700
if (t.flags & (TypeFlags.Literal | TypeFlags.Null | TypeFlags.Undefined)) {
17701
17701
text += getTemplateStringForType(t) || "";
17702
17702
text += texts[i + 1];
@@ -17719,6 +17719,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
17719
17719
}
17720
17720
}
17721
17721
17722
+ function stripObjectTypeTags(type: Type) {
17723
+ if (type.flags & TypeFlags.Intersection) {
17724
+ const nonObjectTypes = filter((type as IntersectionType).types, t => !(t.flags & TypeFlags.Object));
17725
+ if (nonObjectTypes !== (type as IntersectionType).types) {
17726
+ return getIntersectionType(nonObjectTypes);
17727
+ }
17728
+ }
17729
+ return type;
17730
+ }
17731
+
17722
17732
function getTemplateStringForType(type: Type) {
17723
17733
return type.flags & TypeFlags.StringLiteral ? (type as StringLiteralType).value :
17724
17734
type.flags & TypeFlags.NumberLiteral ? "" + (type as NumberLiteralType).value :
@@ -18052,26 +18062,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
18052
18062
}
18053
18063
18054
18064
function isPatternLiteralPlaceholderType(type: Type): boolean {
18055
- if (type.flags & TypeFlags.Intersection) {
18056
- // Return true if the intersection consists of one or more placeholders and zero or
18057
- // more object type tags.
18058
- let seenPlaceholder = false;
18059
- for (const t of (type as IntersectionType).types) {
18060
- if (t.flags & (TypeFlags.Literal | TypeFlags.Nullable) || isPatternLiteralPlaceholderType(t)) {
18061
- seenPlaceholder = true;
18062
- }
18063
- else if (!(t.flags & TypeFlags.Object)) {
18064
- return false;
18065
- }
18066
- }
18067
- return seenPlaceholder;
18068
- }
18069
- return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || isPatternLiteralType(type);
18065
+ return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt) ||
18066
+ isPatternLiteralType(type) ||
18067
+ type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isPatternLiteralType));
18070
18068
}
18071
18069
18072
18070
function isPatternLiteralType(type: Type) {
18073
18071
// A pattern literal type is a template literal or a string mapping type that contains only
18074
- // non-generic pattern literal placeholders.
18072
+ // non-generic pattern literal placeholders. Assumptions are made elsewhere that pattern literal
18073
+ // contain no generics. For example, pattern literal types can be key types in index signatures.
18075
18074
return !!(type.flags & TypeFlags.TemplateLiteral) && every((type as TemplateLiteralType).types, isPatternLiteralPlaceholderType) ||
18076
18075
!!(type.flags & TypeFlags.StringMapping) && isPatternLiteralPlaceholderType((type as StringMappingType).type);
18077
18076
}
0 commit comments