Associate type alias names with union, intersection and literal types

This commit is contained in:
Anders Hejlsberg 2016-07-18 17:31:17 -07:00
parent 7d1c2fcf70
commit a17bd026e5
2 changed files with 36 additions and 18 deletions

View File

@ -2133,6 +2133,10 @@ namespace ts {
else if (type.flags & TypeFlags.Tuple) {
writeTupleType(<TupleType>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(<UnionOrIntersectionType>type, flags);
}
@ -3704,8 +3708,9 @@ namespace ts {
return unknownType;
}
let type: Type;
const typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
let declaration: JSDocTypedefTag | TypeAliasDeclaration = <JSDocTypedefTag>getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag);
let type: Type;
if (declaration) {
if (declaration.jsDocTypeLiteral) {
type = getTypeFromTypeNode(declaration.jsDocTypeLiteral);
@ -3716,12 +3721,12 @@ namespace ts {
}
else {
declaration = <TypeAliasDeclaration>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] = <UnionType>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> = T & { next: List<T> }" 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] = <IntersectionType>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(<TupleTypeNode>node);
case SyntaxKind.UnionType:
case SyntaxKind.JSDocUnionType:
return getTypeFromUnionTypeNode(<UnionTypeNode>node);
return getTypeFromUnionTypeNode(<UnionTypeNode>node, aliasSymbol, aliasTypeArguments);
case SyntaxKind.IntersectionType:
return getTypeFromIntersectionTypeNode(<IntersectionTypeNode>node);
return getTypeFromIntersectionTypeNode(<IntersectionTypeNode>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 = <AnonymousType>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((<TupleType>type).elementTypes, mapper, instantiateType));
}
if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) {
return getUnionType(instantiateList((<UnionType>type).types, mapper, instantiateType), /*noSubtypeReduction*/ true);
return getUnionType(instantiateList((<UnionType>type).types, mapper, instantiateType), /*noSubtypeReduction*/ true, type.aliasSymbol, mapper.targetTypes);
}
if (type.flags & TypeFlags.Intersection) {
return getIntersectionType(instantiateList((<IntersectionType>type).types, mapper, instantiateType));
return getIntersectionType(instantiateList((<IntersectionType>type).types, mapper, instantiateType), type.aliasSymbol, mapper.targetTypes);
}
}
return type;

View File

@ -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).