@@ -5030,6 +5030,7 @@ namespace ts {
5030
5030
case SyntaxKind.JSDocTemplateTag:
5031
5031
case SyntaxKind.MappedType:
5032
5032
case SyntaxKind.ConditionalType:
5033
+ case SyntaxKind.TypeParameter:
5033
5034
const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes);
5034
5035
if (node.kind === SyntaxKind.MappedType) {
5035
5036
return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode((<MappedTypeNode>node).typeParameter)));
@@ -5058,8 +5059,8 @@ namespace ts {
5058
5059
let result: TypeParameter[];
5059
5060
for (const node of symbol.declarations) {
5060
5061
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;
5063
5064
const typeParameters = getEffectiveTypeParameterDeclarations(declaration);
5064
5065
if (typeParameters) {
5065
5066
result = appendTypeParameters(result, typeParameters);
@@ -5484,6 +5485,13 @@ namespace ts {
5484
5485
const type = <TypeParameter>createType(TypeFlags.TypeParameter);
5485
5486
type.symbol = symbol;
5486
5487
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
+ }
5487
5495
}
5488
5496
return <TypeParameter>links.declaredType;
5489
5497
}
@@ -7445,8 +7453,14 @@ namespace ts {
7445
7453
}
7446
7454
else {
7447
7455
const constraintDeclaration = getConstraintDeclaration(typeParameter);
7448
- typeParameter. constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) :
7456
+ let constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) :
7449
7457
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;
7450
7464
}
7451
7465
}
7452
7466
return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint;
@@ -7528,6 +7542,9 @@ namespace ts {
7528
7542
const typeParameters = type.localTypeParameters;
7529
7543
if (typeParameters) {
7530
7544
const numTypeArguments = length(node.typeArguments);
7545
+ if (numTypeArguments === 0 && isGenericTypeArgument(node)) {
7546
+ return type;
7547
+ }
7531
7548
const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
7532
7549
const isJs = isInJavaScriptFile(node);
7533
7550
const isJsImplicitAny = !noImplicitAny && isJs;
@@ -7594,6 +7611,56 @@ namespace ts {
7594
7611
return checkNoTypeArguments(node, symbol) ? type : unknownType;
7595
7612
}
7596
7613
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
+
7597
7664
function getTypeReferenceName(node: TypeReferenceType): EntityNameOrEntityNameExpression | undefined {
7598
7665
switch (node.kind) {
7599
7666
case SyntaxKind.TypeReference:
@@ -7686,6 +7753,10 @@ namespace ts {
7686
7753
(symbol.members || getJSDocClassTag(symbol.valueDeclaration))) {
7687
7754
return getInferredClassType(symbol);
7688
7755
}
7756
+
7757
+ if (symbol.flags & SymbolFlags.TypeParameter) {
7758
+ return getTypeFromTypeParameterReference(node, symbol, typeArguments);
7759
+ }
7689
7760
}
7690
7761
7691
7762
function getSubstitutionType(typeVariable: TypeVariable, substitute: Type) {
@@ -9304,6 +9375,9 @@ namespace ts {
9304
9375
function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
9305
9376
const result = <TypeParameter>createType(TypeFlags.TypeParameter);
9306
9377
result.symbol = typeParameter.symbol;
9378
+ result.typeParameters = typeParameter.typeParameters;
9379
+ result.typeArguments = typeParameter.typeArguments;
9380
+ result.genericTarget = typeParameter.genericTarget;
9307
9381
result.target = typeParameter;
9308
9382
return result;
9309
9383
}
@@ -9538,7 +9612,27 @@ namespace ts {
9538
9612
function instantiateType(type: Type, mapper: TypeMapper): Type {
9539
9613
if (type && mapper && mapper !== identityMapper) {
9540
9614
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
+ }
9542
9636
}
9543
9637
if (type.flags & TypeFlags.Object) {
9544
9638
if ((<ObjectType>type).objectFlags & ObjectFlags.Anonymous) {
@@ -9817,7 +9911,8 @@ namespace ts {
9817
9911
(getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable);
9818
9912
const related = callbacks ?
9819
9913
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);
9821
9916
if (!related) {
9822
9917
if (reportErrors) {
9823
9918
errorReporter(Diagnostics.Types_of_parameters_0_and_1_are_incompatible,
@@ -10808,6 +10903,9 @@ namespace ts {
10808
10903
const sourceIsPrimitive = !!(source.flags & TypeFlags.Primitive);
10809
10904
if (relation !== identityRelation) {
10810
10905
source = getApparentType(source);
10906
+ if (target.flags & TypeFlags.TypeParameter && (<TypeParameter>target).typeParameters) {
10907
+ target = getApparentType(target);
10908
+ }
10811
10909
}
10812
10910
// In a check of the form X = A & B, we will have previously checked if A relates to X or B relates
10813
10911
// 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 {
12260
12358
inference.topLevel = false;
12261
12359
}
12262
12360
}
12263
- return;
12264
12361
}
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;
12265
12368
}
12266
12369
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
12267
12370
// If source and target are references to the same generic type, infer from type arguments
@@ -12378,6 +12481,7 @@ namespace ts {
12378
12481
12379
12482
function getInferenceInfoForType(type: Type) {
12380
12483
if (type.flags & TypeFlags.TypeVariable) {
12484
+ type = (<TypeParameter>type).genericTarget || type;
12381
12485
for (const inference of inferences) {
12382
12486
if (type === inference.typeParameter) {
12383
12487
return inference;
@@ -20573,6 +20677,7 @@ namespace ts {
20573
20677
20574
20678
checkSourceElement(node.constraint);
20575
20679
checkSourceElement(node.default);
20680
+ checkTypeParameters(node.typeParameters);
20576
20681
const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node));
20577
20682
if (!hasNonCircularBaseConstraint(typeParameter)) {
20578
20683
error(node.constraint, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(typeParameter));
@@ -21212,6 +21317,21 @@ namespace ts {
21212
21317
return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters)));
21213
21318
}
21214
21319
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
+
21215
21335
function checkTypeQuery(node: TypeQueryNode) {
21216
21336
getTypeFromTypeQueryNode(node);
21217
21337
}
@@ -23822,6 +23942,7 @@ namespace ts {
23822
23942
}
23823
23943
}
23824
23944
23945
+ // TODO: Update to handle type parameters with type parameters
23825
23946
function areTypeParametersIdentical(declarations: ReadonlyArray<ClassDeclaration | InterfaceDeclaration>, targetParameters: TypeParameter[]) {
23826
23947
const maxTypeArgumentCount = length(targetParameters);
23827
23948
const minTypeArgumentCount = getMinTypeArgumentCount(targetParameters);
0 commit comments