@@ -421,6 +421,7 @@ import {
421421 hasSyntacticModifier,
422422 hasSyntacticModifiers,
423423 hasType,
424+ hasTypeArguments,
424425 HeritageClause,
425426 hostGetCanonicalFileName,
426427 Identifier,
@@ -42620,6 +42621,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4262042621 return undefined;
4262142622 }
4262242623
42624+ /**
42625+ * Gets generic signatures from the function's/constructor's type.
42626+ */
42627+ function getUninstantiatedSignatures(node: CallLikeExpression): readonly Signature[] {
42628+ switch (node.kind) {
42629+ case SyntaxKind.CallExpression:
42630+ case SyntaxKind.Decorator:
42631+ return getSignaturesOfType(
42632+ getTypeOfExpression(node.expression),
42633+ SignatureKind.Call,
42634+ );
42635+ case SyntaxKind.NewExpression:
42636+ return getSignaturesOfType(
42637+ getTypeOfExpression(node.expression),
42638+ SignatureKind.Construct,
42639+ );
42640+ case SyntaxKind.JsxSelfClosingElement:
42641+ case SyntaxKind.JsxOpeningElement:
42642+ if (isJsxIntrinsicTagName(node.tagName)) return [];
42643+ return getSignaturesOfType(
42644+ getTypeOfExpression(node.tagName),
42645+ SignatureKind.Call,
42646+ );
42647+ case SyntaxKind.TaggedTemplateExpression:
42648+ return getSignaturesOfType(
42649+ getTypeOfExpression(node.tag),
42650+ SignatureKind.Call,
42651+ );
42652+ case SyntaxKind.BinaryExpression:
42653+ case SyntaxKind.JsxOpeningFragment:
42654+ return [];
42655+ }
42656+ }
42657+
42658+ function getTypeParameterConstraintForPositionAcrossSignatures(signatures: readonly Signature[], position: number) {
42659+ const relevantTypeParameterConstraints = flatMap(signatures, signature => {
42660+ const relevantTypeParameter = signature.typeParameters?.[position];
42661+ if (relevantTypeParameter === undefined) return [];
42662+ const relevantConstraint = getConstraintOfTypeParameter(relevantTypeParameter);
42663+ if (relevantConstraint === undefined) return [];
42664+ return [relevantConstraint];
42665+ });
42666+ return getUnionType(relevantTypeParameterConstraints);
42667+ }
42668+
4262342669 function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) {
4262442670 checkGrammarTypeArguments(node, node.typeArguments);
4262542671 if (node.kind === SyntaxKind.TypeReference && !isInJSFile(node) && !isInJSDoc(node) && node.typeArguments && node.typeName.end !== node.typeArguments.pos) {
@@ -42658,12 +42704,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4265842704 }
4265942705
4266042706 function getTypeArgumentConstraint(node: TypeNode): Type | undefined {
42661- const typeReferenceNode = tryCast(node.parent, isTypeReferenceType);
42662- if (!typeReferenceNode) return undefined;
42663- const typeParameters = getTypeParametersForTypeReferenceOrImport(typeReferenceNode);
42664- if (!typeParameters) return undefined;
42665- const constraint = getConstraintOfTypeParameter(typeParameters[typeReferenceNode.typeArguments!.indexOf(node)]);
42666- return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters)));
42707+ let typeArgumentPosition;
42708+ if (hasTypeArguments(node.parent) && Array.isArray(node.parent.typeArguments)) {
42709+ typeArgumentPosition = node.parent.typeArguments.indexOf(node);
42710+ }
42711+
42712+ if (typeArgumentPosition !== undefined) {
42713+ // The node could be a type argument of a call, a `new` expression, a decorator, an
42714+ // instantiation expression, or a generic type instantiation.
42715+
42716+ if (isCallLikeExpression(node.parent)) {
42717+ return getTypeParameterConstraintForPositionAcrossSignatures(
42718+ getUninstantiatedSignatures(node.parent),
42719+ typeArgumentPosition,
42720+ );
42721+ }
42722+
42723+ if (isDecorator(node.parent.parent)) {
42724+ return getTypeParameterConstraintForPositionAcrossSignatures(
42725+ getUninstantiatedSignatures(node.parent.parent),
42726+ typeArgumentPosition,
42727+ );
42728+ }
42729+
42730+ if (isExpressionWithTypeArguments(node.parent) && isExpressionStatement(node.parent.parent)) {
42731+ const uninstantiatedType = checkExpression(node.parent.expression);
42732+
42733+ const callConstraint = getTypeParameterConstraintForPositionAcrossSignatures(
42734+ getSignaturesOfType(uninstantiatedType, SignatureKind.Call),
42735+ typeArgumentPosition,
42736+ );
42737+ const constructConstraint = getTypeParameterConstraintForPositionAcrossSignatures(
42738+ getSignaturesOfType(uninstantiatedType, SignatureKind.Construct),
42739+ typeArgumentPosition,
42740+ );
42741+
42742+ // An instantiation expression instantiates both call and construct signatures, so
42743+ // if both exist type arguments must be assignable to both constraints.
42744+ if (constructConstraint.flags & TypeFlags.Never) return callConstraint;
42745+ if (callConstraint.flags & TypeFlags.Never) return constructConstraint;
42746+ return getIntersectionType([callConstraint, constructConstraint]);
42747+ }
42748+
42749+ if (isTypeReferenceType(node.parent)) {
42750+ const typeParameters = getTypeParametersForTypeReferenceOrImport(node.parent);
42751+ if (!typeParameters) return undefined;
42752+ const relevantTypeParameter = typeParameters[typeArgumentPosition];
42753+ const constraint = getConstraintOfTypeParameter(relevantTypeParameter);
42754+ return constraint && instantiateType(
42755+ constraint,
42756+ createTypeMapper(typeParameters, getEffectiveTypeArguments(node.parent, typeParameters)),
42757+ );
42758+ }
42759+ }
4266742760 }
4266842761
4266942762 function checkTypeQuery(node: TypeQueryNode) {
0 commit comments