From a17bd026e535b5ff2c359fc5e793269c6742b23f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Jul 2016 17:31:17 -0700 Subject: [PATCH] Associate type alias names with union, intersection and literal types --- src/compiler/checker.ts | 51 ++++++++++++++++++++++++++--------------- src/compiler/types.ts | 3 +++ 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 641b96bf6c4..33c6e750f16 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2133,6 +2133,10 @@ namespace ts { else if (type.flags & TypeFlags.Tuple) { writeTupleType(type); } + else if (type.flags & (TypeFlags.Anonymous | TypeFlags.UnionOrIntersection) && type.aliasSymbol) { + const typeArguments = type.aliasTypeArguments; + writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, flags); + } else if (type.flags & TypeFlags.UnionOrIntersection) { writeUnionOrIntersectionType(type, flags); } @@ -3704,8 +3708,9 @@ namespace ts { return unknownType; } - let type: Type; + const typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); let declaration: JSDocTypedefTag | TypeAliasDeclaration = getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag); + let type: Type; if (declaration) { if (declaration.jsDocTypeLiteral) { type = getTypeFromTypeNode(declaration.jsDocTypeLiteral); @@ -3716,12 +3721,12 @@ namespace ts { } else { declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); - type = getTypeFromTypeNode(declaration.type); + type = getTypeFromTypeNode(declaration.type, symbol, typeParameters); } if (popTypeResolution()) { - links.typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); - if (links.typeParameters) { + links.typeParameters = typeParameters; + if (typeParameters) { // Initialize the instantiation cache for generic type aliases. The declared type corresponds to // an instantiation of the type alias with the type parameters supplied as type arguments. links.instantiations = {}; @@ -5226,7 +5231,7 @@ namespace ts { // literals and the || and ?: operators). Named types can circularly reference themselves and therefore // cannot be deduplicated during their declaration. For example, "type Item = string | (() => Item" is // a named type that circularly references itself. - function getUnionType(types: Type[], noSubtypeReduction?: boolean): Type { + function getUnionType(types: Type[], noSubtypeReduction?: boolean, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { if (types.length === 0) { return neverType; } @@ -5260,14 +5265,16 @@ namespace ts { const propagatedFlags = getPropagatingFlagsOfTypes(typeSet, /*excludeKinds*/ TypeFlags.Nullable); type = unionTypes[id] = createObjectType(TypeFlags.Union | propagatedFlags); type.types = typeSet; + type.aliasSymbol = aliasSymbol; + type.aliasTypeArguments = aliasTypeArguments; } return type; } - function getTypeFromUnionTypeNode(node: UnionTypeNode): Type { + function getTypeFromUnionTypeNode(node: UnionTypeNode, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - links.resolvedType = getUnionType(map(node.types, getTypeFromTypeNode), /*noSubtypeReduction*/ true); + links.resolvedType = getUnionType(map(node.types, getTypeFromTypeNode), /*noSubtypeReduction*/ true, aliasSymbol, aliasTypeArguments); } return links.resolvedType; } @@ -5277,7 +5284,7 @@ namespace ts { // a type alias of the form "type List = T & { next: List }" cannot be reduced during its declaration. // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution // for intersections of types with signatures can be deterministic. - function getIntersectionType(types: Type[]): Type { + function getIntersectionType(types: Type[], aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { if (types.length === 0) { return emptyObjectType; } @@ -5299,23 +5306,28 @@ namespace ts { const propagatedFlags = getPropagatingFlagsOfTypes(typeSet, /*excludeKinds*/ TypeFlags.Nullable); type = intersectionTypes[id] = createObjectType(TypeFlags.Intersection | propagatedFlags); type.types = typeSet; + type.aliasSymbol = aliasSymbol; + type.aliasTypeArguments = aliasTypeArguments; } return type; } - function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type { + function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - links.resolvedType = getIntersectionType(map(node.types, getTypeFromTypeNode)); + links.resolvedType = getIntersectionType(map(node.types, getTypeFromTypeNode), aliasSymbol, aliasTypeArguments); } return links.resolvedType; } - function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node): Type { + function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { const links = getNodeLinks(node); if (!links.resolvedType) { // Deferred resolution of members is handled by resolveObjectTypeMembers - links.resolvedType = createObjectType(TypeFlags.Anonymous, node.symbol); + const type = createObjectType(TypeFlags.Anonymous, node.symbol); + type.aliasSymbol = aliasSymbol; + type.aliasTypeArguments = aliasTypeArguments; + links.resolvedType = type; } return links.resolvedType; } @@ -5378,7 +5390,7 @@ namespace ts { return links.resolvedType; } - function getTypeFromTypeNode(node: TypeNode): Type { + function getTypeFromTypeNode(node: TypeNode, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { switch (node.kind) { case SyntaxKind.AnyKeyword: case SyntaxKind.JSDocAllType: @@ -5421,9 +5433,9 @@ namespace ts { return getTypeFromTupleTypeNode(node); case SyntaxKind.UnionType: case SyntaxKind.JSDocUnionType: - return getTypeFromUnionTypeNode(node); + return getTypeFromUnionTypeNode(node, aliasSymbol, aliasTypeArguments); case SyntaxKind.IntersectionType: - return getTypeFromIntersectionTypeNode(node); + return getTypeFromIntersectionTypeNode(node, aliasSymbol, aliasTypeArguments); case SyntaxKind.ParenthesizedType: case SyntaxKind.JSDocNullableType: case SyntaxKind.JSDocNonNullableType: @@ -5437,7 +5449,7 @@ namespace ts { case SyntaxKind.JSDocTypeLiteral: case SyntaxKind.JSDocFunctionType: case SyntaxKind.JSDocRecordType: - return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); + return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node, aliasSymbol, aliasTypeArguments); // This function assumes that an identifier or qualified name is a type expression // Callers should first ensure this by calling isTypeNode case SyntaxKind.Identifier: @@ -5490,6 +5502,7 @@ namespace ts { count == 2 ? createBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) : createArrayTypeMapper(sources, targets); mapper.mappedTypes = sources; + mapper.targetTypes = targets; return mapper; } @@ -5615,6 +5628,8 @@ namespace ts { const result = createObjectType(TypeFlags.Anonymous | TypeFlags.Instantiated, type.symbol); result.target = type; result.mapper = mapper; + result.aliasSymbol = type.aliasSymbol; + result.aliasTypeArguments = mapper.targetTypes; mapper.instantiations[type.id] = result; return result; } @@ -5692,10 +5707,10 @@ namespace ts { return createTupleType(instantiateList((type).elementTypes, mapper, instantiateType)); } if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) { - return getUnionType(instantiateList((type).types, mapper, instantiateType), /*noSubtypeReduction*/ true); + return getUnionType(instantiateList((type).types, mapper, instantiateType), /*noSubtypeReduction*/ true, type.aliasSymbol, mapper.targetTypes); } if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(instantiateList((type).types, mapper, instantiateType)); + return getIntersectionType(instantiateList((type).types, mapper, instantiateType), type.aliasSymbol, mapper.targetTypes); } } return type; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3d1962826d1..e9ffb8bff72 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2283,6 +2283,8 @@ namespace ts { /* @internal */ id: number; // Unique ID symbol?: Symbol; // Symbol associated with type (if any) pattern?: DestructuringPattern; // Destructuring pattern represented by type (if any) + aliasSymbol?: Symbol; // Alias associated with type + aliasTypeArguments?: Type[]; // Alias type arguments (if any) } /* @internal */ @@ -2446,6 +2448,7 @@ namespace ts { export interface TypeMapper { (t: TypeParameter): Type; mappedTypes?: Type[]; // Types mapped by this mapper + targetTypes?: Type[]; // Types substituted for mapped types instantiations?: Type[]; // Cache of instantiations created using this type mapper. context?: InferenceContext; // The inference context this mapper was created from. // Only inference mappers have this set (in createInferenceMapper).