@@ -971,6 +971,7 @@ namespace ts {
971971 let deferredGlobalAsyncIterableIteratorType: GenericType | undefined;
972972 let deferredGlobalAsyncGeneratorType: GenericType | undefined;
973973 let deferredGlobalTemplateStringsArrayType: ObjectType | undefined;
974+ let deferredGlobalTemplateStringsArrayOfSymbol: Symbol | undefined;
974975 let deferredGlobalImportMetaType: ObjectType;
975976 let deferredGlobalImportMetaExpressionType: ObjectType;
976977 let deferredGlobalImportCallOptionsType: ObjectType | undefined;
@@ -14102,6 +14103,11 @@ namespace ts {
1410214103 return (deferredGlobalBigIntType ||= getGlobalType("BigInt" as __String, /*arity*/ 0, /*reportErrors*/ false)) || emptyObjectType;
1410314104 }
1410414105
14106+ function getGlobalTemplateStringsArrayOfSymbol(): Symbol | undefined {
14107+ deferredGlobalTemplateStringsArrayOfSymbol ||= getGlobalTypeAliasSymbol("TemplateStringsArrayOf" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol;
14108+ return deferredGlobalTemplateStringsArrayOfSymbol === unknownSymbol ? undefined : deferredGlobalTemplateStringsArrayOfSymbol;
14109+ }
14110+
1410514111 /**
1410614112 * Instantiates a global type that is generic with some element type, and returns that instantiation.
1410714113 */
@@ -21171,6 +21177,43 @@ namespace ts {
2117121177 return isArrayType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType);
2117221178 }
2117321179
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+
2117421217 function getSingleBaseForNonAugmentingSubtype(type: Type) {
2117521218 if (!(getObjectFlags(type) & ObjectFlags.Reference) || !(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface)) {
2117621219 return undefined;
@@ -22830,68 +22873,69 @@ namespace ts {
2283022873 }
2283122874 // Infer from the members of source and target only if the two types are possibly related
2283222875 if (!typesDefinitelyUnrelated(source, target)) {
22833- if (isArrayOrTupleType(source)) {
22876+ const sourceArrayOrTuple = tryGetNonShadowedArrayOrTupleType(source);
22877+ if (sourceArrayOrTuple) {
2283422878 if (isTupleType(target)) {
22835- const sourceArity = getTypeReferenceArity(source );
22879+ const sourceArity = getTypeReferenceArity(sourceArrayOrTuple );
2283622880 const targetArity = getTypeReferenceArity(target);
2283722881 const elementTypes = getTypeArguments(target);
2283822882 const elementFlags = target.target.elementFlags;
2283922883 // When source and target are tuple types with the same structure (fixed, variadic, and rest are matched
2284022884 // 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)) {
2284222886 for (let i = 0; i < targetArity; i++) {
22843- inferFromTypes(getTypeArguments(source )[i], elementTypes[i]);
22887+ inferFromTypes(getTypeArguments(sourceArrayOrTuple )[i], elementTypes[i]);
2284422888 }
2284522889 return;
2284622890 }
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,
2284922893 target.target.hasRestElement ? getEndElementCount(target.target, ElementFlags.Fixed) : 0);
2285022894 // Infer between starting fixed elements.
2285122895 for (let i = 0; i < startLength; i++) {
22852- inferFromTypes(getTypeArguments(source )[i], elementTypes[i]);
22896+ inferFromTypes(getTypeArguments(sourceArrayOrTuple )[i], elementTypes[i]);
2285322897 }
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) {
2285522899 // 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];
2285722901 for (let i = startLength; i < targetArity - endLength; i++) {
2285822902 inferFromTypes(elementFlags[i] & ElementFlags.Variadic ? createArrayType(restType) : restType, elementTypes[i]);
2285922903 }
2286022904 }
2286122905 else {
2286222906 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 )) {
2286422908 // Middle of target is [...T, ...U] and source is tuple type
2286522909 const targetInfo = getInferenceInfoForType(elementTypes[startLength]);
2286622910 if (targetInfo && targetInfo.impliedArity !== undefined) {
2286722911 // 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]);
2287022914 }
2287122915 }
2287222916 else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Variadic) {
2287322917 // Middle of target is exactly one variadic element. Infer the slice between the fixed parts in the source.
2287422918 // If target ends in optional element(s), make a lower priority a speculative inference.
2287522919 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]);
2287722921 inferWithPriority(sourceSlice, elementTypes[startLength], endsInOptional ? InferencePriority.SpeculativeTuple : 0);
2287822922 }
2287922923 else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Rest) {
2288022924 // 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];
2288222926 if (restType) {
2288322927 inferFromTypes(restType, elementTypes[startLength]);
2288422928 }
2288522929 }
2288622930 }
2288722931 // Infer between ending fixed elements
2288822932 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]);
2289022934 }
2289122935 return;
2289222936 }
2289322937 if (isArrayType(target)) {
22894- inferFromIndexTypes(source , target);
22938+ inferFromIndexTypes(sourceArrayOrTuple , target);
2289522939 return;
2289622940 }
2289722941 }
@@ -27548,7 +27592,37 @@ namespace ts {
2754827592 return checkIteratedTypeOrElementType(IterationUse.Spread, arrayOrIterableType, undefinedType, node.expression);
2754927593 }
2755027594
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+
2755127608 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+ }
2755227626 return node.isSpread ? getIndexedAccessType(node.type, numberType) : node.type;
2755327627 }
2755427628
@@ -30587,10 +30661,10 @@ namespace ts {
3058730661 let typeArguments: NodeArray<TypeNode> | undefined;
3058830662
3058930663 if (!isDecorator) {
30590- typeArguments = ( node as CallExpression) .typeArguments;
30664+ typeArguments = node.typeArguments;
3059130665
3059230666 // 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) {
3059430668 forEach(typeArguments, checkSourceElement);
3059530669 }
3059630670 }
0 commit comments