@@ -5128,6 +5128,7 @@ namespace ts {
51285128 case SyntaxKind.JSDocTemplateTag:
51295129 case SyntaxKind.MappedType:
51305130 case SyntaxKind.ConditionalType:
5131+ case SyntaxKind.TypeParameter:
51315132 const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes);
51325133 if (node.kind === SyntaxKind.MappedType) {
51335134 return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode((<MappedTypeNode>node).typeParameter)));
@@ -5156,8 +5157,8 @@ namespace ts {
51565157 let result: TypeParameter[];
51575158 for (const node of symbol.declarations) {
51585159 if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.ClassDeclaration ||
5159- node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.TypeAliasDeclaration) {
5160- const declaration = <InterfaceDeclaration | TypeAliasDeclaration>node;
5160+ node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.TypeAliasDeclaration || node.kind === SyntaxKind.TypeParameter ) {
5161+ const declaration = <InterfaceDeclaration | TypeAliasDeclaration | TypeParameterDeclaration >node;
51615162 const typeParameters = getEffectiveTypeParameterDeclarations(declaration);
51625163 if (typeParameters) {
51635164 result = appendTypeParameters(result, typeParameters);
@@ -5582,6 +5583,13 @@ namespace ts {
55825583 const type = <TypeParameter>createType(TypeFlags.TypeParameter);
55835584 type.symbol = symbol;
55845585 links.declaredType = type;
5586+
5587+ const typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
5588+ if (typeParameters) {
5589+ links.instantiations = createMap<TypeParameter>();
5590+ links.instantiations.set(getTypeListId(typeParameters), type);
5591+ type.typeParameters = typeParameters;
5592+ }
55855593 }
55865594 return <TypeParameter>links.declaredType;
55875595 }
@@ -7553,8 +7561,14 @@ namespace ts {
75537561 }
75547562 else {
75557563 const constraintDeclaration = getConstraintDeclaration(typeParameter);
7556- typeParameter. constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) :
7564+ let constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) :
75577565 getInferredTypeParameterConstraint(typeParameter) || noConstraintType;
7566+ if (constraint !== noConstraintType && typeParameter.typeParameters) {
7567+ const apparentMapper = createTypeMapper(typeParameter.typeParameters, map(typeParameter.typeParameters, getApparentType));
7568+ const argumentMapper = typeParameter.typeArguments ? createTypeMapper(typeParameter.typeParameters, typeParameter.typeArguments) : identityMapper;
7569+ constraint = instantiateType(constraint, combineTypeMappers(argumentMapper, apparentMapper));
7570+ }
7571+ typeParameter.constraint = constraint;
75587572 }
75597573 }
75607574 return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint;
@@ -7636,6 +7650,9 @@ namespace ts {
76367650 const typeParameters = type.localTypeParameters;
76377651 if (typeParameters) {
76387652 const numTypeArguments = length(node.typeArguments);
7653+ if (numTypeArguments === 0 && isGenericTypeArgument(node)) {
7654+ return type;
7655+ }
76397656 const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
76407657 const isJs = isInJavaScriptFile(node);
76417658 const isJsImplicitAny = !noImplicitAny && isJs;
@@ -7702,6 +7719,56 @@ namespace ts {
77027719 return checkNoTypeArguments(node, symbol) ? type : unknownType;
77037720 }
77047721
7722+ function getTypeFromTypeParameterReference(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[]): Type {
7723+ const type = <TypeParameter>getDeclaredTypeOfSymbol(symbol);
7724+ const typeParameters = type.typeParameters;
7725+ if (typeParameters) {
7726+ const numTypeArguments = length(typeArguments);
7727+ if (numTypeArguments === 0 && isGenericTypeArgument(node)) {
7728+ return type;
7729+ }
7730+ const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
7731+ if (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length) {
7732+ error(node,
7733+ minTypeArgumentCount === typeParameters.length
7734+ ? Diagnostics.Generic_type_0_requires_1_type_argument_s
7735+ : Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments,
7736+ symbolToString(symbol),
7737+ minTypeArgumentCount,
7738+ typeParameters.length);
7739+ return unknownType;
7740+ }
7741+ const id = getTypeListId(typeArguments);
7742+ const links = getSymbolLinks(symbol);
7743+ let reference = <TypeParameter>links.instantiations.get(id);
7744+ if (!reference) {
7745+ reference = getTypeParameterReference(type, typeArguments);
7746+ links.instantiations.set(id, reference);
7747+ }
7748+ return reference;
7749+ }
7750+ else if (!checkNoTypeArguments(node, symbol)) {
7751+ return unknownType;
7752+ }
7753+ return getConstrainedTypeVariable(type, node);
7754+ }
7755+
7756+ function getTypeParameterReference(genericTypeParameter: TypeParameter, typeArguments: Type[]): TypeParameter {
7757+ Debug.assert(genericTypeParameter.genericTarget === undefined && genericTypeParameter.typeParameters && genericTypeParameter.typeParameters.length === typeArguments.length);
7758+ const id = getTypeListId(typeArguments);
7759+ const links = getSymbolLinks(genericTypeParameter.symbol);
7760+ let reference = <TypeParameter>links.instantiations.get(id);
7761+ if (!reference) {
7762+ reference = <TypeParameter>createType(TypeFlags.TypeParameter);
7763+ reference.symbol = genericTypeParameter.symbol;
7764+ reference.typeParameters = genericTypeParameter.typeParameters;
7765+ reference.typeArguments = typeArguments;
7766+ reference.genericTarget = genericTypeParameter;
7767+ links.instantiations.set(id, reference);
7768+ }
7769+ return reference;
7770+ }
7771+
77057772 function getTypeReferenceName(node: TypeReferenceType): EntityNameOrEntityNameExpression | undefined {
77067773 switch (node.kind) {
77077774 case SyntaxKind.TypeReference:
@@ -7794,6 +7861,10 @@ namespace ts {
77947861 (symbol.members || getJSDocClassTag(symbol.valueDeclaration))) {
77957862 return getInferredClassType(symbol);
77967863 }
7864+
7865+ if (symbol.flags & SymbolFlags.TypeParameter) {
7866+ return getTypeFromTypeParameterReference(node, symbol, typeArguments);
7867+ }
77977868 }
77987869
77997870 function getSubstitutionType(typeVariable: TypeVariable, substitute: Type) {
@@ -9412,6 +9483,9 @@ namespace ts {
94129483 function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
94139484 const result = <TypeParameter>createType(TypeFlags.TypeParameter);
94149485 result.symbol = typeParameter.symbol;
9486+ result.typeParameters = typeParameter.typeParameters;
9487+ result.typeArguments = typeParameter.typeArguments;
9488+ result.genericTarget = typeParameter.genericTarget;
94159489 result.target = typeParameter;
94169490 return result;
94179491 }
@@ -9646,7 +9720,27 @@ namespace ts {
96469720 function instantiateType(type: Type, mapper: TypeMapper): Type {
96479721 if (type && mapper && mapper !== identityMapper) {
96489722 if (type.flags & TypeFlags.TypeParameter) {
9649- return mapper(<TypeParameter>type);
9723+ if ((<TypeParameter>type).typeParameters && (<TypeParameter>type).genericTarget) {
9724+ const newType = mapper((<TypeParameter>type).genericTarget);
9725+ if (newType.flags & TypeFlags.TypeParameter && (<TypeParameter>newType).typeParameters) {
9726+ // Mapper did not instantiate the generic type so just create another reference to it.
9727+ const newTypeArguments = instantiateTypes((<TypeParameter>type).typeArguments, mapper);
9728+ return getTypeParameterReference(<TypeParameter>newType, newTypeArguments);
9729+ }
9730+ const orginalNewTypeArguments = (<TypeReference>newType).typeArguments;
9731+ if (!orginalNewTypeArguments) {
9732+ // this means it was instantiated as anonymous type without type arguments.
9733+ return newType;
9734+ }
9735+ if (length(orginalNewTypeArguments) !== length((<TypeParameter>type).typeArguments)) {
9736+ return newType;
9737+ }
9738+ const newTypeArguments = instantiateTypes((<TypeParameter>type).typeArguments, mapper);
9739+ return createTypeReference((<TypeReference>newType).target, newTypeArguments);
9740+ }
9741+ else {
9742+ return mapper(<TypeParameter>type);
9743+ }
96509744 }
96519745 if (type.flags & TypeFlags.Object) {
96529746 if ((<ObjectType>type).objectFlags & ObjectFlags.Anonymous) {
@@ -9925,7 +10019,8 @@ namespace ts {
992510019 (getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable);
992610020 const related = callbacks ?
992710021 compareSignaturesRelated(targetSig, sourceSig, strictVariance ? CallbackCheck.Strict : CallbackCheck.Bivariant, /*ignoreReturnTypes*/ false, reportErrors, errorReporter, compareTypes) :
9928- !callbackCheck && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
10022+ !callbackCheck && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) ||
10023+ compareTypes(targetType, sourceType, reportErrors);
992910024 if (!related) {
993010025 if (reportErrors) {
993110026 errorReporter(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
@@ -10915,6 +11010,9 @@ namespace ts {
1091511010 const sourceIsPrimitive = !!(source.flags & TypeFlags.Primitive);
1091611011 if (relation !== identityRelation) {
1091711012 source = getApparentType(source);
11013+ if (target.flags & TypeFlags.TypeParameter && (<TypeParameter>target).typeParameters) {
11014+ target = getApparentType(target);
11015+ }
1091811016 }
1091911017 // In a check of the form X = A & B, we will have previously checked if A relates to X or B relates
1092011018 // to X. Failing both of those we want to check if the aggregation of A and B's members structurally
@@ -12367,8 +12465,13 @@ namespace ts {
1236712465 inference.topLevel = false;
1236812466 }
1236912467 }
12370- return;
1237112468 }
12469+ if (target.flags & TypeFlags.TypeParameter && (<TypeParameter>target).typeArguments && forEach((<TypeParameter>target).typeArguments, couldContainTypeVariables) && getConstraintOfTypeParameter(<TypeParameter>target)) {
12470+ // This is a generic type parameter reference and it might contain other type parameters to infer
12471+ // so infer from the constraint of the type parameter (which is where the other type parameters would be if they are referenced)
12472+ inferFromTypes(source, getConstraintOfTypeParameter(<TypeParameter>target));
12473+ }
12474+ return;
1237212475 }
1237312476 if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
1237412477 // If source and target are references to the same generic type, infer from type arguments
@@ -12485,6 +12588,7 @@ namespace ts {
1248512588
1248612589 function getInferenceInfoForType(type: Type) {
1248712590 if (type.flags & TypeFlags.TypeVariable) {
12591+ type = (<TypeParameter>type).genericTarget || type;
1248812592 for (const inference of inferences) {
1248912593 if (type === inference.typeParameter) {
1249012594 return inference;
@@ -20680,6 +20784,7 @@ namespace ts {
2068020784
2068120785 checkSourceElement(node.constraint);
2068220786 checkSourceElement(node.default);
20787+ checkTypeParameters(node.typeParameters);
2068320788 const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node));
2068420789 if (!hasNonCircularBaseConstraint(typeParameter)) {
2068520790 error(node.constraint, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(typeParameter));
@@ -21319,6 +21424,21 @@ namespace ts {
2131921424 return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters)));
2132021425 }
2132121426
21427+ function isGenericTypeArgument(node: NodeWithTypeArguments): boolean {
21428+ if (!isTypeReferenceType(node.parent)) {
21429+ return false;
21430+ }
21431+ const name = getTypeReferenceName(node.parent);
21432+ const identifier = getFirstIdentifier(name);
21433+ const symbol = resolveEntityName(identifier, SymbolFlags.Type, /*ignoreErrors*/ true);
21434+ const typeParameters = symbol && getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
21435+ if (!typeParameters) {
21436+ return false;
21437+ }
21438+ const typeParameter = typeParameters[node.parent.typeArguments.indexOf(node)!];
21439+ return !!length(typeParameter.typeParameters);
21440+ }
21441+
2132221442 function checkTypeQuery(node: TypeQueryNode) {
2132321443 getTypeFromTypeQueryNode(node);
2132421444 }
@@ -23946,6 +24066,7 @@ namespace ts {
2394624066 }
2394724067 }
2394824068
24069+ // TODO: Update to handle type parameters with type parameters
2394924070 function areTypeParametersIdentical(declarations: ReadonlyArray<ClassDeclaration | InterfaceDeclaration>, targetParameters: TypeParameter[]) {
2395024071 const maxTypeArgumentCount = length(targetParameters);
2395124072 const minTypeArgumentCount = getMinTypeArgumentCount(targetParameters);
0 commit comments