@@ -2904,16 +2904,17 @@ module ts {
29042904 }
29052905
29062906 function getPropertiesOfType(type: Type): Symbol[] {
2907- if (type.flags & TypeFlags.Union) {
2908- return getPropertiesOfUnionType(<UnionType>type);
2909- }
2910- return getPropertiesOfObjectType(getApparentType(type));
2907+ type = getApparentType(type);
2908+ return type.flags & TypeFlags.Union ? getPropertiesOfUnionType(<UnionType>type) : getPropertiesOfObjectType(type);
29112909 }
29122910
29132911 // For a type parameter, return the base constraint of the type parameter. For the string, number,
29142912 // boolean, and symbol primitive types, return the corresponding object types. Otherwise return the
29152913 // type itself. Note that the apparent type of a union type is the union type itself.
29162914 function getApparentType(type: Type): Type {
2915+ if (type.flags & TypeFlags.Union) {
2916+ type = getReducedTypeOfUnionType(<UnionType>type);
2917+ }
29172918 if (type.flags & TypeFlags.TypeParameter) {
29182919 do {
29192920 type = getConstraintOfTypeParameter(<TypeParameter>type);
@@ -2986,27 +2987,27 @@ module ts {
29862987 // necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from
29872988 // Object and Function as appropriate.
29882989 function getPropertyOfType(type: Type, name: string): Symbol {
2989- if (type.flags & TypeFlags.Union) {
2990- return getPropertyOfUnionType(<UnionType>type, name);
2991- }
2992- if (!(type.flags & TypeFlags.ObjectType)) {
2993- type = getApparentType(type);
2994- if (!(type.flags & TypeFlags.ObjectType)) {
2995- return undefined;
2990+ type = getApparentType(type);
2991+ if (type.flags & TypeFlags.ObjectType) {
2992+ let resolved = resolveObjectOrUnionTypeMembers(type);
2993+ if (hasProperty(resolved.members, name)) {
2994+ let symbol = resolved.members[name];
2995+ if (symbolIsValue(symbol)) {
2996+ return symbol;
2997+ }
29962998 }
2997- }
2998- let resolved = resolveObjectOrUnionTypeMembers(type);
2999- if (hasProperty(resolved.members, name)) {
3000- let symbol = resolved.members[name];
3001- if (symbolIsValue(symbol)) {
3002- return symbol;
2999+ if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
3000+ let symbol = getPropertyOfObjectType(globalFunctionType, name);
3001+ if (symbol) {
3002+ return symbol;
3003+ }
30033004 }
3005+ return getPropertyOfObjectType(globalObjectType, name);
30043006 }
3005- if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
3006- let symbol = getPropertyOfObjectType(globalFunctionType, name);
3007- if (symbol) return symbol;
3007+ if (type.flags & TypeFlags.Union) {
3008+ return getPropertyOfUnionType(<UnionType>type, name);
30083009 }
3009- return getPropertyOfObjectType(globalObjectType, name) ;
3010+ return undefined ;
30103011 }
30113012
30123013 function getSignaturesOfObjectOrUnionType(type: Type, kind: SignatureKind): Signature[] {
@@ -3581,6 +3582,10 @@ module ts {
35813582 }
35823583 }
35833584
3585+ // The noSubtypeReduction flag is there because it isn't possible to always do subtype reduction. The flag
3586+ // is true when creating a union type from a type node and when instantiating a union type. In both of those
3587+ // cases subtype reduction has to be deferred to properly support recursive union types. For example, a
3588+ // type alias of the form "type Item = string | (() => Item)" cannot be reduced during its declaration.
35843589 function getUnionType(types: Type[], noSubtypeReduction?: boolean): Type {
35853590 if (types.length === 0) {
35863591 return emptyObjectType;
@@ -3605,10 +3610,19 @@ module ts {
36053610 if (!type) {
36063611 type = unionTypes[id] = <UnionType>createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(sortedTypes));
36073612 type.types = sortedTypes;
3613+ type.reducedType = noSubtypeReduction ? undefined : type;
36083614 }
36093615 return type;
36103616 }
36113617
3618+ function getReducedTypeOfUnionType(type: UnionType): Type {
3619+ // If union type was created without subtype reduction, perform the deferred reduction now
3620+ if (!type.reducedType) {
3621+ type.reducedType = getUnionType(type.types, /*noSubtypeReduction*/ false);
3622+ }
3623+ return type.reducedType;
3624+ }
3625+
36123626 function getTypeFromUnionTypeNode(node: UnionTypeNode): Type {
36133627 let links = getNodeLinks(node);
36143628 if (!links.resolvedType) {
0 commit comments