Allow new alias to be associated with type alias instantiation

This commit is contained in:
Anders Hejlsberg 2021-01-08 11:40:55 -10:00
parent e388a2642a
commit 2c2d06dfe1
2 changed files with 25 additions and 14 deletions

View file

@ -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 ? (<UnionType>type).origin : undefined;
const types = origin && origin.flags & TypeFlags.UnionOrIntersection ? (<UnionOrIntersectionType>origin).types : (<UnionOrIntersectionType>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((<IndexType>type).type, mapper));
@ -15649,7 +15656,9 @@ namespace ts {
return getStringMappingType((<StringMappingType>type).symbol, instantiateType((<StringMappingType>type).type, mapper));
}
if (flags & TypeFlags.IndexedAccess) {
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper), (<IndexedAccessType>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((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper), (<IndexedAccessType>type).noUncheckedIndexedAccessCandidate, /*accessNode*/ undefined, newAliasSymbol, newAliasTypeArguments);
}
if (flags & TypeFlags.Conditional) {
return getConditionalTypeInstantiation(<ConditionalType>type, combineTypeMappers((<ConditionalType>type).mapper, mapper));

View file

@ -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<string, Type>; // 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<SymbolId, TransientSymbol>; // 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