@@ -5030,6 +5030,7 @@ namespace ts {
50305030 case SyntaxKind.JSDocTemplateTag:
50315031 case SyntaxKind.MappedType:
50325032 case SyntaxKind.ConditionalType:
5033+ case SyntaxKind.TypeParameter:
50335034 const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes);
50345035 if (node.kind === SyntaxKind.MappedType) {
50355036 return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode((<MappedTypeNode>node).typeParameter)));
@@ -5058,8 +5059,8 @@ namespace ts {
50585059 let result: TypeParameter[];
50595060 for (const node of symbol.declarations) {
50605061 if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.ClassDeclaration ||
5061- node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.TypeAliasDeclaration) {
5062- const declaration = <InterfaceDeclaration | TypeAliasDeclaration>node;
5062+ node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.TypeAliasDeclaration || node.kind === SyntaxKind.TypeParameter ) {
5063+ const declaration = <InterfaceDeclaration | TypeAliasDeclaration | TypeParameterDeclaration >node;
50635064 const typeParameters = getEffectiveTypeParameterDeclarations(declaration);
50645065 if (typeParameters) {
50655066 result = appendTypeParameters(result, typeParameters);
@@ -5484,6 +5485,13 @@ namespace ts {
54845485 const type = <TypeParameter>createType(TypeFlags.TypeParameter);
54855486 type.symbol = symbol;
54865487 links.declaredType = type;
5488+
5489+ const typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
5490+ if (typeParameters) {
5491+ links.instantiations = createMap<TypeParameter>();
5492+ links.instantiations.set(getTypeListId(typeParameters), type);
5493+ type.typeParameters = typeParameters;
5494+ }
54875495 }
54885496 return <TypeParameter>links.declaredType;
54895497 }
@@ -7445,8 +7453,14 @@ namespace ts {
74457453 }
74467454 else {
74477455 const constraintDeclaration = getConstraintDeclaration(typeParameter);
7448- typeParameter. constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) :
7456+ let constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) :
74497457 getInferredTypeParameterConstraint(typeParameter) || noConstraintType;
7458+ if (constraint !== noConstraintType && typeParameter.typeParameters) {
7459+ const apparentMapper = createTypeMapper(typeParameter.typeParameters, map(typeParameter.typeParameters, getApparentType));
7460+ const argumentMapper = typeParameter.typeArguments ? createTypeMapper(typeParameter.typeParameters, typeParameter.typeArguments) : identityMapper;
7461+ constraint = instantiateType(constraint, combineTypeMappers(argumentMapper, apparentMapper));
7462+ }
7463+ typeParameter.constraint = constraint;
74507464 }
74517465 }
74527466 return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint;
@@ -7528,6 +7542,9 @@ namespace ts {
75287542 const typeParameters = type.localTypeParameters;
75297543 if (typeParameters) {
75307544 const numTypeArguments = length(node.typeArguments);
7545+ if (numTypeArguments === 0 && isGenericTypeArgument(node)) {
7546+ return type;
7547+ }
75317548 const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
75327549 const isJs = isInJavaScriptFile(node);
75337550 const isJsImplicitAny = !noImplicitAny && isJs;
@@ -7594,6 +7611,56 @@ namespace ts {
75947611 return checkNoTypeArguments(node, symbol) ? type : unknownType;
75957612 }
75967613
7614+ function getTypeFromTypeParameterReference(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[]): Type {
7615+ const type = <TypeParameter>getDeclaredTypeOfSymbol(symbol);
7616+ const typeParameters = type.typeParameters;
7617+ if (typeParameters) {
7618+ const numTypeArguments = length(typeArguments);
7619+ if (numTypeArguments === 0 && isGenericTypeArgument(node)) {
7620+ return type;
7621+ }
7622+ const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
7623+ if (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length) {
7624+ error(node,
7625+ minTypeArgumentCount === typeParameters.length
7626+ ? Diagnostics.Generic_type_0_requires_1_type_argument_s
7627+ : Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments,
7628+ symbolToString(symbol),
7629+ minTypeArgumentCount,
7630+ typeParameters.length);
7631+ return unknownType;
7632+ }
7633+ const id = getTypeListId(typeArguments);
7634+ const links = getSymbolLinks(symbol);
7635+ let reference = <TypeParameter>links.instantiations.get(id);
7636+ if (!reference) {
7637+ reference = getTypeParameterReference(type, typeArguments);
7638+ links.instantiations.set(id, reference);
7639+ }
7640+ return reference;
7641+ }
7642+ else if (!checkNoTypeArguments(node, symbol)) {
7643+ return unknownType;
7644+ }
7645+ return getConstrainedTypeVariable(type, node);
7646+ }
7647+
7648+ function getTypeParameterReference(genericTypeParameter: TypeParameter, typeArguments: Type[]): TypeParameter {
7649+ Debug.assert(genericTypeParameter.genericTarget === undefined && genericTypeParameter.typeParameters && genericTypeParameter.typeParameters.length === typeArguments.length);
7650+ const id = getTypeListId(typeArguments);
7651+ const links = getSymbolLinks(genericTypeParameter.symbol);
7652+ let reference = <TypeParameter>links.instantiations.get(id);
7653+ if (!reference) {
7654+ reference = <TypeParameter>createType(TypeFlags.TypeParameter);
7655+ reference.symbol = genericTypeParameter.symbol;
7656+ reference.typeParameters = genericTypeParameter.typeParameters;
7657+ reference.typeArguments = typeArguments;
7658+ reference.genericTarget = genericTypeParameter;
7659+ links.instantiations.set(id, reference);
7660+ }
7661+ return reference;
7662+ }
7663+
75977664 function getTypeReferenceName(node: TypeReferenceType): EntityNameOrEntityNameExpression | undefined {
75987665 switch (node.kind) {
75997666 case SyntaxKind.TypeReference:
@@ -7686,6 +7753,10 @@ namespace ts {
76867753 (symbol.members || getJSDocClassTag(symbol.valueDeclaration))) {
76877754 return getInferredClassType(symbol);
76887755 }
7756+
7757+ if (symbol.flags & SymbolFlags.TypeParameter) {
7758+ return getTypeFromTypeParameterReference(node, symbol, typeArguments);
7759+ }
76897760 }
76907761
76917762 function getSubstitutionType(typeVariable: TypeVariable, substitute: Type) {
@@ -9304,6 +9375,9 @@ namespace ts {
93049375 function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
93059376 const result = <TypeParameter>createType(TypeFlags.TypeParameter);
93069377 result.symbol = typeParameter.symbol;
9378+ result.typeParameters = typeParameter.typeParameters;
9379+ result.typeArguments = typeParameter.typeArguments;
9380+ result.genericTarget = typeParameter.genericTarget;
93079381 result.target = typeParameter;
93089382 return result;
93099383 }
@@ -9538,7 +9612,27 @@ namespace ts {
95389612 function instantiateType(type: Type, mapper: TypeMapper): Type {
95399613 if (type && mapper && mapper !== identityMapper) {
95409614 if (type.flags & TypeFlags.TypeParameter) {
9541- return mapper(<TypeParameter>type);
9615+ if ((<TypeParameter>type).typeParameters && (<TypeParameter>type).genericTarget) {
9616+ const newType = mapper((<TypeParameter>type).genericTarget);
9617+ if (newType.flags & TypeFlags.TypeParameter && (<TypeParameter>newType).typeParameters) {
9618+ // Mapper did not instantiate the generic type so just create another reference to it.
9619+ const newTypeArguments = instantiateTypes((<TypeParameter>type).typeArguments, mapper);
9620+ return getTypeParameterReference(<TypeParameter>newType, newTypeArguments);
9621+ }
9622+ const orginalNewTypeArguments = (<TypeReference>newType).typeArguments;
9623+ if (!orginalNewTypeArguments) {
9624+ // this means it was instantiated as anonymous type without type arguments.
9625+ return newType;
9626+ }
9627+ if (length(orginalNewTypeArguments) !== length((<TypeParameter>type).typeArguments)) {
9628+ return newType;
9629+ }
9630+ const newTypeArguments = instantiateTypes((<TypeParameter>type).typeArguments, mapper);
9631+ return createTypeReference((<TypeReference>newType).target, newTypeArguments);
9632+ }
9633+ else {
9634+ return mapper(<TypeParameter>type);
9635+ }
95429636 }
95439637 if (type.flags & TypeFlags.Object) {
95449638 if ((<ObjectType>type).objectFlags & ObjectFlags.Anonymous) {
@@ -9817,7 +9911,8 @@ namespace ts {
98179911 (getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable);
98189912 const related = callbacks ?
98199913 compareSignaturesRelated(targetSig, sourceSig, strictVariance ? CallbackCheck.Strict : CallbackCheck.Bivariant, /*ignoreReturnTypes*/ false, reportErrors, errorReporter, compareTypes) :
9820- !callbackCheck && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
9914+ !callbackCheck && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) ||
9915+ compareTypes(targetType, sourceType, reportErrors);
98219916 if (!related) {
98229917 if (reportErrors) {
98239918 errorReporter(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
@@ -10808,6 +10903,9 @@ namespace ts {
1080810903 const sourceIsPrimitive = !!(source.flags & TypeFlags.Primitive);
1080910904 if (relation !== identityRelation) {
1081010905 source = getApparentType(source);
10906+ if (target.flags & TypeFlags.TypeParameter && (<TypeParameter>target).typeParameters) {
10907+ target = getApparentType(target);
10908+ }
1081110909 }
1081210910 // In a check of the form X = A & B, we will have previously checked if A relates to X or B relates
1081310911 // to X. Failing both of those we want to check if the aggregation of A and B's members structurally
@@ -12260,8 +12358,13 @@ namespace ts {
1226012358 inference.topLevel = false;
1226112359 }
1226212360 }
12263- return;
1226412361 }
12362+ if (target.flags & TypeFlags.TypeParameter && (<TypeParameter>target).typeArguments && forEach((<TypeParameter>target).typeArguments, couldContainTypeVariables) && getConstraintOfTypeParameter(<TypeParameter>target)) {
12363+ // This is a generic type parameter reference and it might contain other type parameters to infer
12364+ // so infer from the constraint of the type parameter (which is where the other type parameters would be if they are referenced)
12365+ inferFromTypes(source, getConstraintOfTypeParameter(<TypeParameter>target));
12366+ }
12367+ return;
1226512368 }
1226612369 if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
1226712370 // If source and target are references to the same generic type, infer from type arguments
@@ -12378,6 +12481,7 @@ namespace ts {
1237812481
1237912482 function getInferenceInfoForType(type: Type) {
1238012483 if (type.flags & TypeFlags.TypeVariable) {
12484+ type = (<TypeParameter>type).genericTarget || type;
1238112485 for (const inference of inferences) {
1238212486 if (type === inference.typeParameter) {
1238312487 return inference;
@@ -20573,6 +20677,7 @@ namespace ts {
2057320677
2057420678 checkSourceElement(node.constraint);
2057520679 checkSourceElement(node.default);
20680+ checkTypeParameters(node.typeParameters);
2057620681 const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node));
2057720682 if (!hasNonCircularBaseConstraint(typeParameter)) {
2057820683 error(node.constraint, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(typeParameter));
@@ -21212,6 +21317,21 @@ namespace ts {
2121221317 return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters)));
2121321318 }
2121421319
21320+ function isGenericTypeArgument(node: NodeWithTypeArguments): boolean {
21321+ if (!isTypeReferenceType(node.parent)) {
21322+ return false;
21323+ }
21324+ const name = getTypeReferenceName(node.parent);
21325+ const identifier = getFirstIdentifier(name);
21326+ const symbol = resolveEntityName(identifier, SymbolFlags.Type, /*ignoreErrors*/ true);
21327+ const typeParameters = symbol && getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
21328+ if (!typeParameters) {
21329+ return false;
21330+ }
21331+ const typeParameter = typeParameters[node.parent.typeArguments.indexOf(node)!];
21332+ return !!length(typeParameter.typeParameters);
21333+ }
21334+
2121521335 function checkTypeQuery(node: TypeQueryNode) {
2121621336 getTypeFromTypeQueryNode(node);
2121721337 }
@@ -23822,6 +23942,7 @@ namespace ts {
2382223942 }
2382323943 }
2382423944
23945+ // TODO: Update to handle type parameters with type parameters
2382523946 function areTypeParametersIdentical(declarations: ReadonlyArray<ClassDeclaration | InterfaceDeclaration>, targetParameters: TypeParameter[]) {
2382623947 const maxTypeArgumentCount = length(targetParameters);
2382723948 const minTypeArgumentCount = getMinTypeArgumentCount(targetParameters);
0 commit comments