diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f2fb60dc5fc..34f50ace455 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12375,17 +12375,19 @@ namespace ts { return checkNoTypeArguments(node, symbol) ? type : errorType; } - function getTypeAliasInstantiation(symbol: Symbol, typeArguments: readonly Type[] | undefined): Type { + function getTypeAliasInstantiation(symbol: Symbol, typeArguments: readonly Type[] | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { const type = getDeclaredTypeOfSymbol(symbol); if (type === intrinsicMarkerType && intrinsicTypeKinds.has(symbol.escapedName as string) && typeArguments && typeArguments.length === 1) { return getStringMappingType(symbol, typeArguments[0]); } const links = getSymbolLinks(symbol); const typeParameters = links.typeParameters!; - const id = getTypeListId(typeArguments); + const id = getTypeListId(typeArguments) + (aliasSymbol ? `@${getSymbolId(aliasSymbol)}` : ""); let instantiation = links.instantiations!.get(id); if (!instantiation) { - links.instantiations!.set(id, instantiation = instantiateType(type, createTypeMapper(typeParameters, fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters), isInJSFile(symbol.valueDeclaration))))); + links.instantiations!.set(id, instantiation = instantiateType(type, + createTypeMapper(typeParameters, fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters), isInJSFile(symbol.valueDeclaration))), + aliasSymbol, aliasTypeArguments)); } return instantiation; } @@ -12411,7 +12413,8 @@ namespace ts { typeParameters.length); return errorType; } - return getTypeAliasInstantiation(symbol, typeArgumentsFromTypeReferenceNode(node)); + const aliasSymbol = getAliasSymbolForTypeNode(node); + return getTypeAliasInstantiation(symbol, typeArgumentsFromTypeReferenceNode(node), aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol)); } return checkNoTypeArguments(node, symbol) ? type : errorType; } @@ -15591,9 +15594,9 @@ namespace ts { return getConditionalType(root, mapper); } - function instantiateType(type: Type, mapper: TypeMapper | undefined): Type; - function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined; - function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined { + function instantiateType(type: Type, mapper: TypeMapper | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type; + function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type | undefined; + function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type | undefined { if (!(type && mapper && couldContainTypeVariables(type))) { return type; } @@ -15608,12 +15611,12 @@ namespace ts { totalInstantiationCount++; instantiationCount++; instantiationDepth++; - const result = instantiateTypeWorker(type, mapper); + const result = instantiateTypeWorker(type, mapper, aliasSymbol, aliasTypeArguments); instantiationDepth--; return result; } - function instantiateTypeWorker(type: Type, mapper: TypeMapper): Type { + function instantiateTypeWorker(type: Type, mapper: TypeMapper, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined): Type { const flags = type.flags; if (flags & TypeFlags.TypeParameter) { return getMappedType(type, mapper); @@ -15634,10 +15637,14 @@ namespace ts { const origin = type.flags & TypeFlags.Union ? (type).origin : undefined; const types = origin && origin.flags & TypeFlags.UnionOrIntersection ? (origin).types : (type).types; const newTypes = instantiateTypes(types, mapper); - return newTypes === types ? type : - flags & TypeFlags.Intersection || origin && origin.flags & TypeFlags.Intersection ? - getIntersectionType(newTypes, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)) : - getUnionType(newTypes, UnionReduction.Literal, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); + if (newTypes === types && aliasSymbol === type.aliasSymbol) { + return type; + } + const newAliasSymbol = aliasSymbol || type.aliasSymbol; + const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); + return flags & TypeFlags.Intersection || origin && origin.flags & TypeFlags.Intersection ? + getIntersectionType(newTypes, newAliasSymbol, newAliasTypeArguments) : + getUnionType(newTypes, UnionReduction.Literal, newAliasSymbol, newAliasTypeArguments); } if (flags & TypeFlags.Index) { return getIndexType(instantiateType((type).type, mapper)); @@ -15649,7 +15656,9 @@ namespace ts { return getStringMappingType((type).symbol, instantiateType((type).type, mapper)); } if (flags & TypeFlags.IndexedAccess) { - return getIndexedAccessType(instantiateType((type).objectType, mapper), instantiateType((type).indexType, mapper), (type).noUncheckedIndexedAccessCandidate, /*accessNode*/ undefined, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); + const newAliasSymbol = aliasSymbol || type.aliasSymbol; + const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); + return getIndexedAccessType(instantiateType((type).objectType, mapper), instantiateType((type).indexType, mapper), (type).noUncheckedIndexedAccessCandidate, /*accessNode*/ undefined, newAliasSymbol, newAliasTypeArguments); } if (flags & TypeFlags.Conditional) { return getConditionalTypeInstantiation(type, combineTypeMappers((type).mapper, mapper)); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1daa67bcbe8..487615ee507 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4745,6 +4745,8 @@ namespace ts { typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic) outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type instantiations?: ESMap; // Instantiations of generic type alias (undefined if non-generic) + aliasSymbol?: Symbol; // Alias associated with generic type alias instantiation + aliasTypeArguments?: readonly Type[] // Alias type arguments (if any) inferredClassSymbol?: ESMap; // Symbol of an inferred ES5 constructor function mapper?: TypeMapper; // Type mapper for instantiation alias referenced?: boolean; // True if alias symbol has been referenced as a value that can be emitted