@@ -11943,7 +11943,7 @@ namespace ts {
11943
11943
}
11944
11944
if (t.flags & TypeFlags.StringMapping) {
11945
11945
const constraint = getBaseConstraint((t as StringMappingType).type);
11946
- return constraint ? getStringMappingType((t as StringMappingType).symbol, constraint) : stringType;
11946
+ return constraint && constraint !== (t as StringMappingType).type ? getStringMappingType((t as StringMappingType).symbol, constraint) : stringType;
11947
11947
}
11948
11948
if (t.flags & TypeFlags.IndexedAccess) {
11949
11949
const baseObjectType = getBaseConstraint((t as IndexedAccessType).objectType);
@@ -15040,8 +15040,11 @@ namespace ts {
15040
15040
15041
15041
function getStringMappingType(symbol: Symbol, type: Type): Type {
15042
15042
return type.flags & (TypeFlags.Union | TypeFlags.Never) ? mapType(type, t => getStringMappingType(symbol, t)) :
15043
- isGenericIndexType(type) ? getStringMappingTypeForGenericType(symbol, type) :
15043
+ // Mapping<Mapping<T>> === Mapping<T>
15044
+ type.flags & TypeFlags.StringMapping && symbol === type.symbol ? type :
15045
+ isGenericIndexType(type) || isPatternLiteralPlaceholderType(type) ? getStringMappingTypeForGenericType(symbol, isPatternLiteralPlaceholderType(type) && !(type.flags & TypeFlags.StringMapping) ? getTemplateLiteralType(["", ""], [type]) : type) :
15044
15046
type.flags & TypeFlags.StringLiteral ? getStringLiteralType(applyStringMapping(symbol, (type as StringLiteralType).value)) :
15047
+ type.flags & TypeFlags.TemplateLiteral ? getTemplateLiteralType(...applyTemplateStringMapping(symbol, (type as TemplateLiteralType).texts, (type as TemplateLiteralType).types)) :
15045
15048
type;
15046
15049
}
15047
15050
@@ -15055,6 +15058,16 @@ namespace ts {
15055
15058
return str;
15056
15059
}
15057
15060
15061
+ function applyTemplateStringMapping(symbol: Symbol, texts: readonly string[], types: readonly Type[]): [texts: readonly string[], types: readonly Type[]] {
15062
+ switch (intrinsicTypeKinds.get(symbol.escapedName as string)) {
15063
+ case IntrinsicTypeKind.Uppercase: return [texts.map(t => t.toUpperCase()), types.map(t => getStringMappingType(symbol, t))];
15064
+ case IntrinsicTypeKind.Lowercase: return [texts.map(t => t.toLowerCase()), types.map(t => getStringMappingType(symbol, t))];
15065
+ case IntrinsicTypeKind.Capitalize: return [texts[0] === "" ? texts : [texts[0].charAt(0).toUpperCase() + texts[0].slice(1), ...texts.slice(1)], texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types];
15066
+ case IntrinsicTypeKind.Uncapitalize: return [texts[0] === "" ? texts : [texts[0].charAt(0).toLowerCase() + texts[0].slice(1), ...texts.slice(1)], texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types];
15067
+ }
15068
+ return [texts, types];
15069
+ }
15070
+
15058
15071
function getStringMappingTypeForGenericType(symbol: Symbol, type: Type): Type {
15059
15072
const id = `${getSymbolId(symbol)},${getTypeId(type)}`;
15060
15073
let result = stringMappingTypes.get(id);
@@ -15310,8 +15323,8 @@ namespace ts {
15310
15323
accessNode;
15311
15324
}
15312
15325
15313
- function isPatternLiteralPlaceholderType(type: Type) {
15314
- return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt));
15326
+ function isPatternLiteralPlaceholderType(type: Type): boolean {
15327
+ return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || !!(type.flags & TypeFlags.StringMapping && isPatternLiteralPlaceholderType((type as StringMappingType).type)) ;
15315
15328
}
15316
15329
15317
15330
function isPatternLiteralType(type: Type) {
@@ -19168,6 +19181,13 @@ namespace ts {
19168
19181
return Ternary.True;
19169
19182
}
19170
19183
}
19184
+ else if (target.flags & TypeFlags.StringMapping) {
19185
+ if (!(source.flags & TypeFlags.StringMapping)) {
19186
+ if (isUnchangedByStringMapping(target.symbol, source)) {
19187
+ return Ternary.True;
19188
+ }
19189
+ }
19190
+ }
19171
19191
19172
19192
if (source.flags & TypeFlags.TypeVariable) {
19173
19193
// IndexedAccess comparisons are handled above in the `target.flags & TypeFlage.IndexedAccess` branch
@@ -19208,7 +19228,10 @@ namespace ts {
19208
19228
}
19209
19229
}
19210
19230
else if (source.flags & TypeFlags.StringMapping) {
19211
- if (target.flags & TypeFlags.StringMapping && (source as StringMappingType).symbol === (target as StringMappingType).symbol) {
19231
+ if (target.flags & TypeFlags.StringMapping) {
19232
+ if ((source as StringMappingType).symbol !== (target as StringMappingType).symbol) {
19233
+ return Ternary.False;
19234
+ }
19212
19235
if (result = isRelatedTo((source as StringMappingType).type, (target as StringMappingType).type, RecursionFlags.Both, reportErrors)) {
19213
19236
resetErrorInfo(saveErrorInfo);
19214
19237
return result;
@@ -20129,7 +20152,7 @@ namespace ts {
20129
20152
}
20130
20153
}
20131
20154
20132
- return isUnitType(type) || !!(type.flags & TypeFlags.TemplateLiteral);
20155
+ return isUnitType(type) || !!(type.flags & TypeFlags.TemplateLiteral) || !!(type.flags & TypeFlags.StringMapping) ;
20133
20156
}
20134
20157
20135
20158
function getExactOptionalUnassignableProperties(source: Type, target: Type) {
@@ -21625,6 +21648,10 @@ namespace ts {
21625
21648
return success && result === SyntaxKind.BigIntLiteral && scanner.getTextPos() === (s.length + 1) && !(flags & TokenFlags.ContainsSeparator);
21626
21649
}
21627
21650
21651
+ function isUnchangedByStringMapping(symbol: Symbol, value: Type) {
21652
+ return value === getStringMappingType(symbol, value);
21653
+ }
21654
+
21628
21655
function isValidTypeForTemplateLiteralPlaceholder(source: Type, target: Type): boolean {
21629
21656
if (source === target || target.flags & (TypeFlags.Any | TypeFlags.String)) {
21630
21657
return true;
@@ -21633,7 +21660,8 @@ namespace ts {
21633
21660
const value = (source as StringLiteralType).value;
21634
21661
return !!(target.flags & TypeFlags.Number && value !== "" && isFinite(+value) ||
21635
21662
target.flags & TypeFlags.BigInt && value !== "" && isValidBigIntString(value) ||
21636
- target.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) && value === (target as IntrinsicType).intrinsicName);
21663
+ target.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) && value === (target as IntrinsicType).intrinsicName ||
21664
+ target.flags & TypeFlags.StringMapping && isUnchangedByStringMapping(target.symbol, getStringLiteralType(value)));
21637
21665
}
21638
21666
if (source.flags & TypeFlags.TemplateLiteral) {
21639
21667
const texts = (source as TemplateLiteralType).texts;
0 commit comments