@@ -5128,6 +5128,7 @@ namespace ts {
5128
5128
case SyntaxKind.JSDocTemplateTag:
5129
5129
case SyntaxKind.MappedType:
5130
5130
case SyntaxKind.ConditionalType:
5131
+ case SyntaxKind.TypeParameter:
5131
5132
const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes);
5132
5133
if (node.kind === SyntaxKind.MappedType) {
5133
5134
return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode((<MappedTypeNode>node).typeParameter)));
@@ -5156,8 +5157,8 @@ namespace ts {
5156
5157
let result: TypeParameter[];
5157
5158
for (const node of symbol.declarations) {
5158
5159
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;
5161
5162
const typeParameters = getEffectiveTypeParameterDeclarations(declaration);
5162
5163
if (typeParameters) {
5163
5164
result = appendTypeParameters(result, typeParameters);
@@ -5582,6 +5583,13 @@ namespace ts {
5582
5583
const type = <TypeParameter>createType(TypeFlags.TypeParameter);
5583
5584
type.symbol = symbol;
5584
5585
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
+ }
5585
5593
}
5586
5594
return <TypeParameter>links.declaredType;
5587
5595
}
@@ -7553,8 +7561,14 @@ namespace ts {
7553
7561
}
7554
7562
else {
7555
7563
const constraintDeclaration = getConstraintDeclaration(typeParameter);
7556
- typeParameter. constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) :
7564
+ let constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) :
7557
7565
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;
7558
7572
}
7559
7573
}
7560
7574
return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint;
@@ -7636,6 +7650,9 @@ namespace ts {
7636
7650
const typeParameters = type.localTypeParameters;
7637
7651
if (typeParameters) {
7638
7652
const numTypeArguments = length(node.typeArguments);
7653
+ if (numTypeArguments === 0 && isGenericTypeArgument(node)) {
7654
+ return type;
7655
+ }
7639
7656
const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
7640
7657
const isJs = isInJavaScriptFile(node);
7641
7658
const isJsImplicitAny = !noImplicitAny && isJs;
@@ -7702,6 +7719,56 @@ namespace ts {
7702
7719
return checkNoTypeArguments(node, symbol) ? type : unknownType;
7703
7720
}
7704
7721
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
+
7705
7772
function getTypeReferenceName(node: TypeReferenceType): EntityNameOrEntityNameExpression | undefined {
7706
7773
switch (node.kind) {
7707
7774
case SyntaxKind.TypeReference:
@@ -7794,6 +7861,10 @@ namespace ts {
7794
7861
(symbol.members || getJSDocClassTag(symbol.valueDeclaration))) {
7795
7862
return getInferredClassType(symbol);
7796
7863
}
7864
+
7865
+ if (symbol.flags & SymbolFlags.TypeParameter) {
7866
+ return getTypeFromTypeParameterReference(node, symbol, typeArguments);
7867
+ }
7797
7868
}
7798
7869
7799
7870
function getSubstitutionType(typeVariable: TypeVariable, substitute: Type) {
@@ -9412,6 +9483,9 @@ namespace ts {
9412
9483
function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
9413
9484
const result = <TypeParameter>createType(TypeFlags.TypeParameter);
9414
9485
result.symbol = typeParameter.symbol;
9486
+ result.typeParameters = typeParameter.typeParameters;
9487
+ result.typeArguments = typeParameter.typeArguments;
9488
+ result.genericTarget = typeParameter.genericTarget;
9415
9489
result.target = typeParameter;
9416
9490
return result;
9417
9491
}
@@ -9646,7 +9720,27 @@ namespace ts {
9646
9720
function instantiateType(type: Type, mapper: TypeMapper): Type {
9647
9721
if (type && mapper && mapper !== identityMapper) {
9648
9722
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
+ }
9650
9744
}
9651
9745
if (type.flags & TypeFlags.Object) {
9652
9746
if ((<ObjectType>type).objectFlags & ObjectFlags.Anonymous) {
@@ -9925,7 +10019,8 @@ namespace ts {
9925
10019
(getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable);
9926
10020
const related = callbacks ?
9927
10021
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);
9929
10024
if (!related) {
9930
10025
if (reportErrors) {
9931
10026
errorReporter(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
@@ -10915,6 +11010,9 @@ namespace ts {
10915
11010
const sourceIsPrimitive = !!(source.flags & TypeFlags.Primitive);
10916
11011
if (relation !== identityRelation) {
10917
11012
source = getApparentType(source);
11013
+ if (target.flags & TypeFlags.TypeParameter && (<TypeParameter>target).typeParameters) {
11014
+ target = getApparentType(target);
11015
+ }
10918
11016
}
10919
11017
// In a check of the form X = A & B, we will have previously checked if A relates to X or B relates
10920
11018
// 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 {
12367
12465
inference.topLevel = false;
12368
12466
}
12369
12467
}
12370
- return;
12371
12468
}
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;
12372
12475
}
12373
12476
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
12374
12477
// If source and target are references to the same generic type, infer from type arguments
@@ -12485,6 +12588,7 @@ namespace ts {
12485
12588
12486
12589
function getInferenceInfoForType(type: Type) {
12487
12590
if (type.flags & TypeFlags.TypeVariable) {
12591
+ type = (<TypeParameter>type).genericTarget || type;
12488
12592
for (const inference of inferences) {
12489
12593
if (type === inference.typeParameter) {
12490
12594
return inference;
@@ -20680,6 +20784,7 @@ namespace ts {
20680
20784
20681
20785
checkSourceElement(node.constraint);
20682
20786
checkSourceElement(node.default);
20787
+ checkTypeParameters(node.typeParameters);
20683
20788
const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node));
20684
20789
if (!hasNonCircularBaseConstraint(typeParameter)) {
20685
20790
error(node.constraint, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(typeParameter));
@@ -21319,6 +21424,21 @@ namespace ts {
21319
21424
return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters)));
21320
21425
}
21321
21426
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
+
21322
21442
function checkTypeQuery(node: TypeQueryNode) {
21323
21443
getTypeFromTypeQueryNode(node);
21324
21444
}
@@ -23946,6 +24066,7 @@ namespace ts {
23946
24066
}
23947
24067
}
23948
24068
24069
+ // TODO: Update to handle type parameters with type parameters
23949
24070
function areTypeParametersIdentical(declarations: ReadonlyArray<ClassDeclaration | InterfaceDeclaration>, targetParameters: TypeParameter[]) {
23950
24071
const maxTypeArgumentCount = length(targetParameters);
23951
24072
const minTypeArgumentCount = getMinTypeArgumentCount(targetParameters);
0 commit comments