@@ -971,6 +971,7 @@ namespace ts {
971
971
let deferredGlobalAsyncIterableIteratorType: GenericType | undefined;
972
972
let deferredGlobalAsyncGeneratorType: GenericType | undefined;
973
973
let deferredGlobalTemplateStringsArrayType: ObjectType | undefined;
974
+ let deferredGlobalTemplateStringsArrayOfSymbol: Symbol | undefined;
974
975
let deferredGlobalImportMetaType: ObjectType;
975
976
let deferredGlobalImportMetaExpressionType: ObjectType;
976
977
let deferredGlobalImportCallOptionsType: ObjectType | undefined;
@@ -14102,6 +14103,11 @@ namespace ts {
14102
14103
return (deferredGlobalBigIntType ||= getGlobalType("BigInt" as __String, /*arity*/ 0, /*reportErrors*/ false)) || emptyObjectType;
14103
14104
}
14104
14105
14106
+ function getGlobalTemplateStringsArrayOfSymbol(): Symbol | undefined {
14107
+ deferredGlobalTemplateStringsArrayOfSymbol ||= getGlobalTypeAliasSymbol("TemplateStringsArrayOf" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol;
14108
+ return deferredGlobalTemplateStringsArrayOfSymbol === unknownSymbol ? undefined : deferredGlobalTemplateStringsArrayOfSymbol;
14109
+ }
14110
+
14105
14111
/**
14106
14112
* Instantiates a global type that is generic with some element type, and returns that instantiation.
14107
14113
*/
@@ -21171,6 +21177,43 @@ namespace ts {
21171
21177
return isArrayType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType);
21172
21178
}
21173
21179
21180
+ /**
21181
+ * Returns `type` if it is an array or tuple type. If `type` is an intersection type,
21182
+ * returns the rightmost constituent that is an array or tuple type, but only if there are no
21183
+ * other constituents to that contain properties that overlap with array- or tuple- specific
21184
+ * members (i.e., index signatures, numeric string property names, or `length`).
21185
+ */
21186
+ function tryGetNonShadowedArrayOrTupleType(type: Type) {
21187
+ if (isArrayOrTupleType(type)) {
21188
+ return type;
21189
+ }
21190
+
21191
+ if (!(type.flags & TypeFlags.Intersection)) {
21192
+ return undefined;
21193
+ }
21194
+
21195
+ let arrayOrTupleConstituent: TypeReference | undefined;
21196
+ for (const constituent of (type as IntersectionType).types) {
21197
+ if (isArrayOrTupleType(constituent)) {
21198
+ arrayOrTupleConstituent = constituent;
21199
+ }
21200
+ else {
21201
+ const properties = getPropertiesOfType(constituent);
21202
+ for (const property of properties) {
21203
+ if (isNumericLiteralName(property.escapedName) || property.escapedName === "length" as __String) {
21204
+ return undefined;
21205
+ }
21206
+ }
21207
+
21208
+ if (some(getIndexInfosOfType(constituent))) {
21209
+ return undefined;
21210
+ }
21211
+ }
21212
+ }
21213
+
21214
+ return arrayOrTupleConstituent;
21215
+ }
21216
+
21174
21217
function getSingleBaseForNonAugmentingSubtype(type: Type) {
21175
21218
if (!(getObjectFlags(type) & ObjectFlags.Reference) || !(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface)) {
21176
21219
return undefined;
@@ -22830,68 +22873,69 @@ namespace ts {
22830
22873
}
22831
22874
// Infer from the members of source and target only if the two types are possibly related
22832
22875
if (!typesDefinitelyUnrelated(source, target)) {
22833
- if (isArrayOrTupleType(source)) {
22876
+ const sourceArrayOrTuple = tryGetNonShadowedArrayOrTupleType(source);
22877
+ if (sourceArrayOrTuple) {
22834
22878
if (isTupleType(target)) {
22835
- const sourceArity = getTypeReferenceArity(source );
22879
+ const sourceArity = getTypeReferenceArity(sourceArrayOrTuple );
22836
22880
const targetArity = getTypeReferenceArity(target);
22837
22881
const elementTypes = getTypeArguments(target);
22838
22882
const elementFlags = target.target.elementFlags;
22839
22883
// When source and target are tuple types with the same structure (fixed, variadic, and rest are matched
22840
22884
// to the same kind in each position), simply infer between the element types.
22841
- if (isTupleType(source ) && isTupleTypeStructureMatching(source , target)) {
22885
+ if (isTupleType(sourceArrayOrTuple ) && isTupleTypeStructureMatching(sourceArrayOrTuple , target)) {
22842
22886
for (let i = 0; i < targetArity; i++) {
22843
- inferFromTypes(getTypeArguments(source )[i], elementTypes[i]);
22887
+ inferFromTypes(getTypeArguments(sourceArrayOrTuple )[i], elementTypes[i]);
22844
22888
}
22845
22889
return;
22846
22890
}
22847
- const startLength = isTupleType(source ) ? Math.min(source .target.fixedLength, target.target.fixedLength) : 0;
22848
- const endLength = Math.min(isTupleType(source ) ? getEndElementCount(source .target, ElementFlags.Fixed) : 0,
22891
+ const startLength = isTupleType(sourceArrayOrTuple ) ? Math.min(sourceArrayOrTuple .target.fixedLength, target.target.fixedLength) : 0;
22892
+ const endLength = Math.min(isTupleType(sourceArrayOrTuple ) ? getEndElementCount(sourceArrayOrTuple .target, ElementFlags.Fixed) : 0,
22849
22893
target.target.hasRestElement ? getEndElementCount(target.target, ElementFlags.Fixed) : 0);
22850
22894
// Infer between starting fixed elements.
22851
22895
for (let i = 0; i < startLength; i++) {
22852
- inferFromTypes(getTypeArguments(source )[i], elementTypes[i]);
22896
+ inferFromTypes(getTypeArguments(sourceArrayOrTuple )[i], elementTypes[i]);
22853
22897
}
22854
- if (!isTupleType(source ) || sourceArity - startLength - endLength === 1 && source .target.elementFlags[startLength] & ElementFlags.Rest) {
22898
+ if (!isTupleType(sourceArrayOrTuple ) || sourceArity - startLength - endLength === 1 && sourceArrayOrTuple .target.elementFlags[startLength] & ElementFlags.Rest) {
22855
22899
// Single rest element remains in source, infer from that to every element in target
22856
- const restType = getTypeArguments(source )[startLength];
22900
+ const restType = getTypeArguments(sourceArrayOrTuple )[startLength];
22857
22901
for (let i = startLength; i < targetArity - endLength; i++) {
22858
22902
inferFromTypes(elementFlags[i] & ElementFlags.Variadic ? createArrayType(restType) : restType, elementTypes[i]);
22859
22903
}
22860
22904
}
22861
22905
else {
22862
22906
const middleLength = targetArity - startLength - endLength;
22863
- if (middleLength === 2 && elementFlags[startLength] & elementFlags[startLength + 1] & ElementFlags.Variadic && isTupleType(source )) {
22907
+ if (middleLength === 2 && elementFlags[startLength] & elementFlags[startLength + 1] & ElementFlags.Variadic && isTupleType(sourceArrayOrTuple )) {
22864
22908
// Middle of target is [...T, ...U] and source is tuple type
22865
22909
const targetInfo = getInferenceInfoForType(elementTypes[startLength]);
22866
22910
if (targetInfo && targetInfo.impliedArity !== undefined) {
22867
22911
// Infer slices from source based on implied arity of T.
22868
- inferFromTypes(sliceTupleType(source , startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]);
22869
- inferFromTypes(sliceTupleType(source , startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]);
22912
+ inferFromTypes(sliceTupleType(sourceArrayOrTuple , startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]);
22913
+ inferFromTypes(sliceTupleType(sourceArrayOrTuple , startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]);
22870
22914
}
22871
22915
}
22872
22916
else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Variadic) {
22873
22917
// Middle of target is exactly one variadic element. Infer the slice between the fixed parts in the source.
22874
22918
// If target ends in optional element(s), make a lower priority a speculative inference.
22875
22919
const endsInOptional = target.target.elementFlags[targetArity - 1] & ElementFlags.Optional;
22876
- const sourceSlice = isTupleType(source ) ? sliceTupleType(source , startLength, endLength) : createArrayType(getTypeArguments(source )[0]);
22920
+ const sourceSlice = isTupleType(sourceArrayOrTuple ) ? sliceTupleType(sourceArrayOrTuple , startLength, endLength) : createArrayType(getTypeArguments(sourceArrayOrTuple )[0]);
22877
22921
inferWithPriority(sourceSlice, elementTypes[startLength], endsInOptional ? InferencePriority.SpeculativeTuple : 0);
22878
22922
}
22879
22923
else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Rest) {
22880
22924
// Middle of target is exactly one rest element. If middle of source is not empty, infer union of middle element types.
22881
- const restType = isTupleType(source ) ? getElementTypeOfSliceOfTupleType(source , startLength, endLength) : getTypeArguments(source )[0];
22925
+ const restType = isTupleType(sourceArrayOrTuple ) ? getElementTypeOfSliceOfTupleType(sourceArrayOrTuple , startLength, endLength) : getTypeArguments(sourceArrayOrTuple )[0];
22882
22926
if (restType) {
22883
22927
inferFromTypes(restType, elementTypes[startLength]);
22884
22928
}
22885
22929
}
22886
22930
}
22887
22931
// Infer between ending fixed elements
22888
22932
for (let i = 0; i < endLength; i++) {
22889
- inferFromTypes(getTypeArguments(source )[sourceArity - i - 1], elementTypes[targetArity - i - 1]);
22933
+ inferFromTypes(getTypeArguments(sourceArrayOrTuple )[sourceArity - i - 1], elementTypes[targetArity - i - 1]);
22890
22934
}
22891
22935
return;
22892
22936
}
22893
22937
if (isArrayType(target)) {
22894
- inferFromIndexTypes(source , target);
22938
+ inferFromIndexTypes(sourceArrayOrTuple , target);
22895
22939
return;
22896
22940
}
22897
22941
}
@@ -27548,7 +27592,37 @@ namespace ts {
27548
27592
return checkIteratedTypeOrElementType(IterationUse.Spread, arrayOrIterableType, undefinedType, node.expression);
27549
27593
}
27550
27594
27595
+ function getTemplateStringsArrayOf(cookedTypes: Type[], rawTypes: Type[]) {
27596
+ const templateStringsArrayOfAlias = getGlobalTemplateStringsArrayOfSymbol();
27597
+ if (!templateStringsArrayOfAlias) return getGlobalTemplateStringsArrayType();
27598
+ const cookedType = createTupleType(cookedTypes, /*elementFlags*/ undefined, /*readonly*/ true);
27599
+ const rawType = createTupleType(rawTypes, /*elementFlags*/ undefined, /*readonly*/ true);
27600
+ return getTypeAliasInstantiation(templateStringsArrayOfAlias, [cookedType, rawType]);
27601
+ }
27602
+
27603
+ function getRawLiteralType(node: TemplateLiteralLikeNode) {
27604
+ const text = getRawTextOfTemplateLiteralLike(node, getSourceFileOfNode(node));
27605
+ return getStringLiteralType(text);
27606
+ }
27607
+
27551
27608
function checkSyntheticExpression(node: SyntheticExpression): Type {
27609
+ if (isTemplateLiteral(node.parent) && node.type === getGlobalTemplateStringsArrayType()) {
27610
+ const cookedStrings: Type[] = [];
27611
+ const rawStrings: Type[] = [];
27612
+ if (isNoSubstitutionTemplateLiteral(node.parent)) {
27613
+ cookedStrings.push(getStringLiteralType(node.parent.text));
27614
+ rawStrings.push(getRawLiteralType(node.parent));
27615
+ }
27616
+ else {
27617
+ cookedStrings.push(getStringLiteralType(node.parent.head.text));
27618
+ rawStrings.push(getRawLiteralType(node.parent.head));
27619
+ for (const templateSpan of node.parent.templateSpans) {
27620
+ cookedStrings.push(getStringLiteralType(templateSpan.literal.text));
27621
+ rawStrings.push(getRawLiteralType(templateSpan.literal));
27622
+ }
27623
+ }
27624
+ return getTemplateStringsArrayOf(cookedStrings, rawStrings);
27625
+ }
27552
27626
return node.isSpread ? getIndexedAccessType(node.type, numberType) : node.type;
27553
27627
}
27554
27628
@@ -30587,10 +30661,10 @@ namespace ts {
30587
30661
let typeArguments: NodeArray<TypeNode> | undefined;
30588
30662
30589
30663
if (!isDecorator) {
30590
- typeArguments = ( node as CallExpression) .typeArguments;
30664
+ typeArguments = node.typeArguments;
30591
30665
30592
30666
// We already perform checking on the type arguments on the class declaration itself.
30593
- if (isTaggedTemplate || isJsxOpeningOrSelfClosingElement || ( node as CallExpression) .expression.kind !== SyntaxKind.SuperKeyword) {
30667
+ if (isTaggedTemplate || isJsxOpeningOrSelfClosingElement || node.expression.kind !== SyntaxKind.SuperKeyword) {
30594
30668
forEach(typeArguments, checkSourceElement);
30595
30669
}
30596
30670
}
0 commit comments