mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-12 04:17:34 -06:00
Merge pull request #2729 from Microsoft/reducedUnionTypes
Consistently reduce union types
This commit is contained in:
commit
6d36dd5296
@ -2904,16 +2904,17 @@ module ts {
|
||||
}
|
||||
|
||||
function getPropertiesOfType(type: Type): Symbol[] {
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
return getPropertiesOfUnionType(<UnionType>type);
|
||||
}
|
||||
return getPropertiesOfObjectType(getApparentType(type));
|
||||
type = getApparentType(type);
|
||||
return type.flags & TypeFlags.Union ? getPropertiesOfUnionType(<UnionType>type) : getPropertiesOfObjectType(type);
|
||||
}
|
||||
|
||||
// For a type parameter, return the base constraint of the type parameter. For the string, number,
|
||||
// boolean, and symbol primitive types, return the corresponding object types. Otherwise return the
|
||||
// type itself. Note that the apparent type of a union type is the union type itself.
|
||||
function getApparentType(type: Type): Type {
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
type = getReducedTypeOfUnionType(<UnionType>type);
|
||||
}
|
||||
if (type.flags & TypeFlags.TypeParameter) {
|
||||
do {
|
||||
type = getConstraintOfTypeParameter(<TypeParameter>type);
|
||||
@ -2986,27 +2987,27 @@ module ts {
|
||||
// necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from
|
||||
// Object and Function as appropriate.
|
||||
function getPropertyOfType(type: Type, name: string): Symbol {
|
||||
type = getApparentType(type);
|
||||
if (type.flags & TypeFlags.ObjectType) {
|
||||
let resolved = resolveObjectOrUnionTypeMembers(type);
|
||||
if (hasProperty(resolved.members, name)) {
|
||||
let symbol = resolved.members[name];
|
||||
if (symbolIsValue(symbol)) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
|
||||
let symbol = getPropertyOfObjectType(globalFunctionType, name);
|
||||
if (symbol) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
return getPropertyOfObjectType(globalObjectType, name);
|
||||
}
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
return getPropertyOfUnionType(<UnionType>type, name);
|
||||
}
|
||||
if (!(type.flags & TypeFlags.ObjectType)) {
|
||||
type = getApparentType(type);
|
||||
if (!(type.flags & TypeFlags.ObjectType)) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
let resolved = resolveObjectOrUnionTypeMembers(type);
|
||||
if (hasProperty(resolved.members, name)) {
|
||||
let symbol = resolved.members[name];
|
||||
if (symbolIsValue(symbol)) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
|
||||
let symbol = getPropertyOfObjectType(globalFunctionType, name);
|
||||
if (symbol) return symbol;
|
||||
}
|
||||
return getPropertyOfObjectType(globalObjectType, name);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getSignaturesOfObjectOrUnionType(type: Type, kind: SignatureKind): Signature[] {
|
||||
@ -3581,6 +3582,10 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
// The noSubtypeReduction flag is there because it isn't possible to always do subtype reduction. The flag
|
||||
// is true when creating a union type from a type node and when instantiating a union type. In both of those
|
||||
// cases subtype reduction has to be deferred to properly support recursive union types. For example, a
|
||||
// type alias of the form "type Item = string | (() => Item)" cannot be reduced during its declaration.
|
||||
function getUnionType(types: Type[], noSubtypeReduction?: boolean): Type {
|
||||
if (types.length === 0) {
|
||||
return emptyObjectType;
|
||||
@ -3605,10 +3610,19 @@ module ts {
|
||||
if (!type) {
|
||||
type = unionTypes[id] = <UnionType>createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(sortedTypes));
|
||||
type.types = sortedTypes;
|
||||
type.reducedType = noSubtypeReduction ? undefined : type;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function getReducedTypeOfUnionType(type: UnionType): Type {
|
||||
// If union type was created without subtype reduction, perform the deferred reduction now
|
||||
if (!type.reducedType) {
|
||||
type.reducedType = getUnionType(type.types, /*noSubtypeReduction*/ false);
|
||||
}
|
||||
return type.reducedType;
|
||||
}
|
||||
|
||||
function getTypeFromUnionTypeNode(node: UnionTypeNode): Type {
|
||||
let links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
|
||||
@ -1512,6 +1512,8 @@ module ts {
|
||||
export interface UnionType extends Type {
|
||||
types: Type[]; // Constituent types
|
||||
/* @internal */
|
||||
reducedType: Type; // Reduced union type (all subtypes removed)
|
||||
/* @internal */
|
||||
resolvedProperties: SymbolTable; // Cache of resolved properties
|
||||
}
|
||||
|
||||
|
||||
25
tests/baselines/reference/unionTypeReduction.js
Normal file
25
tests/baselines/reference/unionTypeReduction.js
Normal file
@ -0,0 +1,25 @@
|
||||
//// [unionTypeReduction.ts]
|
||||
interface I2 {
|
||||
(): number;
|
||||
(q): boolean;
|
||||
}
|
||||
|
||||
interface I3 {
|
||||
(): number;
|
||||
}
|
||||
|
||||
var i2: I2, i3: I3;
|
||||
|
||||
var e1: I2 | I3;
|
||||
var e2 = i2 || i3; // Type of e2 immediately reduced to I3
|
||||
|
||||
var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature
|
||||
var r2 = e2();
|
||||
|
||||
|
||||
//// [unionTypeReduction.js]
|
||||
var i2, i3;
|
||||
var e1;
|
||||
var e2 = i2 || i3; // Type of e2 immediately reduced to I3
|
||||
var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature
|
||||
var r2 = e2();
|
||||
42
tests/baselines/reference/unionTypeReduction.types
Normal file
42
tests/baselines/reference/unionTypeReduction.types
Normal file
@ -0,0 +1,42 @@
|
||||
=== tests/cases/conformance/types/union/unionTypeReduction.ts ===
|
||||
interface I2 {
|
||||
>I2 : I2, Symbol(I2, Decl(unionTypeReduction.ts, 0, 0))
|
||||
|
||||
(): number;
|
||||
(q): boolean;
|
||||
>q : any, Symbol(q, Decl(unionTypeReduction.ts, 2, 5))
|
||||
}
|
||||
|
||||
interface I3 {
|
||||
>I3 : I3, Symbol(I3, Decl(unionTypeReduction.ts, 3, 1))
|
||||
|
||||
(): number;
|
||||
}
|
||||
|
||||
var i2: I2, i3: I3;
|
||||
>i2 : I2, Symbol(i2, Decl(unionTypeReduction.ts, 9, 3))
|
||||
>I2 : I2, Symbol(I2, Decl(unionTypeReduction.ts, 0, 0))
|
||||
>i3 : I3, Symbol(i3, Decl(unionTypeReduction.ts, 9, 11))
|
||||
>I3 : I3, Symbol(I3, Decl(unionTypeReduction.ts, 3, 1))
|
||||
|
||||
var e1: I2 | I3;
|
||||
>e1 : I2 | I3, Symbol(e1, Decl(unionTypeReduction.ts, 11, 3))
|
||||
>I2 : I2, Symbol(I2, Decl(unionTypeReduction.ts, 0, 0))
|
||||
>I3 : I3, Symbol(I3, Decl(unionTypeReduction.ts, 3, 1))
|
||||
|
||||
var e2 = i2 || i3; // Type of e2 immediately reduced to I3
|
||||
>e2 : I3, Symbol(e2, Decl(unionTypeReduction.ts, 12, 3))
|
||||
>i2 || i3 : I3
|
||||
>i2 : I2, Symbol(i2, Decl(unionTypeReduction.ts, 9, 3))
|
||||
>i3 : I3, Symbol(i3, Decl(unionTypeReduction.ts, 9, 11))
|
||||
|
||||
var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature
|
||||
>r1 : number, Symbol(r1, Decl(unionTypeReduction.ts, 14, 3))
|
||||
>e1() : number
|
||||
>e1 : I2 | I3, Symbol(e1, Decl(unionTypeReduction.ts, 11, 3))
|
||||
|
||||
var r2 = e2();
|
||||
>r2 : number, Symbol(r2, Decl(unionTypeReduction.ts, 15, 3))
|
||||
>e2() : number
|
||||
>e2 : I3, Symbol(e2, Decl(unionTypeReduction.ts, 12, 3))
|
||||
|
||||
16
tests/cases/conformance/types/union/unionTypeReduction.ts
Normal file
16
tests/cases/conformance/types/union/unionTypeReduction.ts
Normal file
@ -0,0 +1,16 @@
|
||||
interface I2 {
|
||||
(): number;
|
||||
(q): boolean;
|
||||
}
|
||||
|
||||
interface I3 {
|
||||
(): number;
|
||||
}
|
||||
|
||||
var i2: I2, i3: I3;
|
||||
|
||||
var e1: I2 | I3;
|
||||
var e2 = i2 || i3; // Type of e2 immediately reduced to I3
|
||||
|
||||
var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature
|
||||
var r2 = e2();
|
||||
@ -2,9 +2,11 @@
|
||||
|
||||
////module E {
|
||||
//// export var n = 1;
|
||||
//// export var x = 0;
|
||||
////}
|
||||
////module F {
|
||||
//// export var n = 1;
|
||||
//// export var y = 0;
|
||||
////}
|
||||
////var q: typeof E | typeof F;
|
||||
////var j = q./*1*/
|
||||
|
||||
@ -19,8 +19,8 @@
|
||||
goTo.marker("propertyReference");
|
||||
verify.definitionCountIs(2);
|
||||
goTo.definition(0);
|
||||
verify.caretAtMarker("propertyDefinition2");
|
||||
verify.caretAtMarker("propertyDefinition1");
|
||||
|
||||
goTo.marker("propertyReference");
|
||||
goTo.definition(1);
|
||||
verify.caretAtMarker("propertyDefinition1");
|
||||
verify.caretAtMarker("propertyDefinition2");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user