Support unions/intersections in spread types

1. Lift unions and intersections above spread types when creating them
in getSpreadType.
2. Cleanup now-unneeded changes to existing union/intersection code.
3. Cleanup some incorrect errors I added earlier.
This commit is contained in:
Nathan Shively-Sanders
2016-10-10 10:05:31 -07:00
parent 0d3f567b0f
commit 4eedfea81f
4 changed files with 135 additions and 158 deletions

View File

@@ -2197,7 +2197,7 @@ namespace ts {
writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, nextFlags);
}
else if (type.flags & TypeFlags.UnionOrIntersection) {
writeUnionOrIntersectionType(<TypeOperatorType>type, nextFlags);
writeUnionOrIntersectionType(<UnionOrIntersectionType>type, nextFlags);
}
else if (type.flags & TypeFlags.Spread) {
writeSpreadType(<SpreadType>type, nextFlags);
@@ -2291,7 +2291,7 @@ namespace ts {
}
}
function writeUnionOrIntersectionType(type: TypeOperatorType, flags: TypeFormatFlags) {
function writeUnionOrIntersectionType(type: UnionOrIntersectionType, flags: TypeFormatFlags) {
if (flags & TypeFormatFlags.InElementType) {
writePunctuation(writer, SyntaxKind.OpenParenToken);
}
@@ -4449,7 +4449,7 @@ namespace ts {
}
}
function getPropertiesOfUnionOrIntersectionType(type: TypeOperatorType): Symbol[] {
function getPropertiesOfUnionOrIntersectionType(type: UnionOrIntersectionType): Symbol[] {
for (const current of type.types) {
for (const prop of getPropertiesOfType(current)) {
getUnionOrIntersectionProperty(type, prop.name);
@@ -4499,7 +4499,7 @@ namespace ts {
}
function getApparentTypeOfSpread(type: SpreadType) {
return getSpreadType([getApparentType(type.left), getApparentType(type.right)], type.symbol, undefined, undefined);
return getSpreadType([getApparentType(type.left), getApparentType(type.right)], type.symbol);
}
/**
@@ -4529,44 +4529,35 @@ namespace ts {
return type;
}
function createUnionOrIntersectionProperty(containingType: TypeOperatorType, name: string): Symbol {
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string) {
const types = containingType.types;
return createUnionOrIntersectionOrSpreadPropertySymbol(containingType, name, () => {
let props: Symbol[];
// Flags we want to propagate to the result if they exist in all source symbols
let commonFlags = (containingType.flags & TypeFlags.Intersection) ? SymbolFlags.Optional : SymbolFlags.None;
let isReadonly = false;
let isPartial = false;
for (const current of types) {
const type = getApparentType(current);
if (type !== unknownType) {
const prop = getPropertyOfType(type, name);
if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected))) {
commonFlags &= prop.flags;
if (!props) {
props = [prop];
}
else if (!contains(props, prop)) {
props.push(prop);
}
if (isReadonlySymbol(prop)) {
isReadonly = true;
}
let props: Symbol[];
// Flags we want to propagate to the result if they exist in all source symbols
let commonFlags = (containingType.flags & TypeFlags.Intersection) ? SymbolFlags.Optional : SymbolFlags.None;
let isReadonly = false;
let isPartial = false;
for (const current of types) {
const type = getApparentType(current);
if (type !== unknownType) {
const prop = getPropertyOfType(type, name);
if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected))) {
commonFlags &= prop.flags;
if (!props) {
props = [prop];
}
else if (!contains(props, prop)) {
props.push(prop);
}
if (isReadonlySymbol(prop)) {
isReadonly = true;
}
}
else if (containingType.flags & TypeFlags.Union) {
isPartial = true;
}
}
else if (containingType.flags & TypeFlags.Union) {
isPartial = true;
}
}
return [props, isReadonly, isPartial, commonFlags];
});
}
function createUnionOrIntersectionOrSpreadPropertySymbol(containingType: TypeOperatorType,
name: string,
symbolCreator: () => [Symbol[], boolean, boolean, SymbolFlags]) {
const [props, isReadonly, isPartial, flags] = symbolCreator();
}
if (!props) {
return undefined;
}
@@ -4590,7 +4581,7 @@ namespace ts {
}
propTypes.push(type);
}
const result = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty | flags, name);
const result = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty | commonFlags, name);
result.syntheticKind === SyntheticSymbolKind.UnionOrIntersection;
result.containingType = containingType;
result.hasNonUniformType = hasNonUniformType;
@@ -4609,7 +4600,7 @@ namespace ts {
// constituents, in which case the isPartial flag is set when the containing type is union type. We need
// these partial properties when identifying discriminant properties, but otherwise they are filtered out
// and do not appear to be present in the union type.
function getUnionOrIntersectionProperty(type: TypeOperatorType, name: string): Symbol {
function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: string): Symbol {
const properties = type.resolvedProperties || (type.resolvedProperties = createMap<Symbol>());
let property = properties[name];
if (!property) {
@@ -4621,7 +4612,7 @@ namespace ts {
return property;
}
function getPropertyOfUnionOrIntersectionType(type: TypeOperatorType, name: string): Symbol {
function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: string): Symbol {
const property = getUnionOrIntersectionProperty(type, name);
// We need to filter out partial properties in union types
return property && !(property.flags & SymbolFlags.SyntheticProperty && (<TransientSymbol>property).isPartial) ? property : undefined;
@@ -4652,7 +4643,7 @@ namespace ts {
return getPropertyOfObjectType(globalObjectType, name);
}
if (type.flags & TypeFlags.UnionOrIntersection) {
return getPropertyOfUnionOrIntersectionType(<TypeOperatorType>type, name);
return getPropertyOfUnionOrIntersectionType(<UnionOrIntersectionType>type, name);
}
return undefined;
}
@@ -5773,6 +5764,9 @@ namespace ts {
return spreadTypes[id];
}
const right = types.pop();
if (right.flags & TypeFlags.Any) {
return anyType;
}
if (right.flags & TypeFlags.Spread) {
// spread is right associative and associativity applies, so transform
// (T ... U) ... V to T ... (U ... V)
@@ -5783,9 +5777,22 @@ namespace ts {
types.push(rspread.right);
return getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments);
}
if (right.flags & TypeFlags.Intersection) {
const spreads = map((right as IntersectionType).types,
t => getSpreadType(types.slice().concat([t]), symbol, aliasSymbol, aliasTypeArguments));
return getIntersectionType(spreads, aliasSymbol, aliasTypeArguments);
}
if (right.flags & TypeFlags.Union) {
// TODO: types is mutable, so this block has to happen before the call to `const left = getSpreadType(...)`
// because that call consumes the array. It might be worthwhile to use a simple linked list here instead.
// It would avoid the slice+concat call that is needed here for multiple calls to getSpreadType.
const spreads = map((right as UnionType).types,
t => getSpreadType(types.slice().concat([t]), symbol, aliasSymbol, aliasTypeArguments));
return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments);
}
const atBeginning = types.length === 0;
const left = getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments);
if (right.flags & (TypeFlags.Null | TypeFlags.Undefined)) {
if (right.flags & TypeFlags.Primitive || left.flags & TypeFlags.Any) {
return left;
}
if (right.flags & TypeFlags.TypeParameter &&
@@ -5795,9 +5802,18 @@ namespace ts {
// for types like T ... T, just return ... T
return left;
}
if (!(right.flags & (TypeFlags.Union | TypeFlags.Intersection | TypeFlags.TypeParameter | TypeFlags.Spread))
&& !(left.flags & (TypeFlags.Union | TypeFlags.Intersection | TypeFlags.TypeParameter | TypeFlags.Spread))) {
const members = createMap<Symbol | undefined>();
if (left.flags & TypeFlags.Intersection) {
const spreads = map((left as IntersectionType).types,
t => getSpreadType(types.slice().concat([t, right]), symbol, aliasSymbol, aliasTypeArguments));
return getIntersectionType(spreads, aliasSymbol, aliasTypeArguments);
}
if (left.flags & TypeFlags.Union) {
const spreads = map((left as UnionType).types,
t => getSpreadType(types.slice().concat([t, right]), symbol, aliasSymbol, aliasTypeArguments));
return getUnionType(spreads, /*subTypeReduction*/ false, aliasSymbol, aliasTypeArguments);
}
if (right.flags & TypeFlags.ObjectType && left.flags & TypeFlags.ObjectType) {
const members = createMap<Symbol>();
const skippedPrivateMembers = createMap<boolean>();
let stringIndexInfo = unionIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String));
let numberIndexInfo = unionIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number));
@@ -5820,7 +5836,6 @@ namespace ts {
for (const leftProp of getPropertiesOfType(left)) {
if (leftProp.flags & SymbolFlags.SetAccessor && !(leftProp.flags & SymbolFlags.GetAccessor)
|| leftProp.name in skippedPrivateMembers) {
// skip set-only properties (methods have already been skipped by the recursive call to getSpreadType)
continue;
}
if (leftProp.name in members) {
@@ -5836,7 +5851,7 @@ namespace ts {
if (declarations.length) {
result.valueDeclaration = declarations[0];
}
result.isReadonly = isReadonlySymbol(rightProp) || isReadonlySymbol(leftProp);
result.isReadonly = isReadonlySymbol(leftProp) || isReadonlySymbol(rightProp);
members[leftProp.name] = result;
}
}
@@ -5846,10 +5861,9 @@ namespace ts {
}
return createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
}
// one side is a type parameter (TODO: Or union or intersection)
const spread = spreadTypes[id] = createObjectType(TypeFlags.Spread, symbol) as SpreadType;
Debug.assert(!!(left.flags & (TypeFlags.Spread | TypeFlags.ObjectType)));
Debug.assert(!!(right.flags & (TypeFlags.TypeParameter | TypeFlags.ObjectType)));
Debug.assert(!!(left.flags & (TypeFlags.Spread | TypeFlags.ObjectType)), "Left flags: " + left.flags.toString(2));
Debug.assert(!!(right.flags & (TypeFlags.TypeParameter | TypeFlags.ObjectType)), "Right flags: " + right.flags.toString(2));
spread.left = left as SpreadType | ResolvedType;
spread.right = right as TypeParameter | ResolvedType;
spread.aliasSymbol = aliasSymbol;
@@ -6802,19 +6816,19 @@ namespace ts {
}
}
if (source.flags & TypeFlags.Spread) {
// you only see this for spreads with type parameters (TODO: and unions/intersections)
if (target.flags & TypeFlags.Spread) {
if (!(spreadTypeRelatedTo(source as SpreadType, target as SpreadType))) {
if (source.flags & TypeFlags.Spread && target.flags & TypeFlags.Spread) {
// you only see this for spreads with type parameters
if (!(spreadTypeRelatedTo(source as SpreadType, target as SpreadType))) {
if (reportErrors) {
reportRelationError(headMessage, source, target);
return Ternary.False;
}
const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo;
const apparentSource = getApparentType(source);
if (result = objectTypeRelatedTo(apparentSource, source, getApparentType(target), reportStructuralErrors)) {
errorInfo = saveErrorInfo;
return result;
}
return Ternary.False;
}
const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo;
const apparentSource = getApparentType(source);
if (result = objectTypeRelatedTo(apparentSource, source, getApparentType(target), reportStructuralErrors)) {
errorInfo = saveErrorInfo;
return result;
}
}
@@ -6878,40 +6892,27 @@ namespace ts {
}
function spreadTypeRelatedTo(source: SpreadType, target: SpreadType): boolean {
// (Spread ... Object) | (Spread | Object ... TypeParameter)
// in other words, if the right side is Object, then the left side must be a Spread.
if (source.right.flags & TypeFlags.ObjectType &&
target.right.flags & TypeFlags.ObjectType) {
// If the right side of a spread type is ObjectType, then the left side must be a Spread.
// Structural compatibility of the spreads' object types are checked separately in isRelatedTo,
// so just skip them for now.
if (source.right.flags & TypeFlags.ObjectType || target.right.flags & TypeFlags.ObjectType) {
return spreadTypeRelatedTo(source.right.flags & TypeFlags.ObjectType ? source.left as SpreadType : source,
target.right.flags & TypeFlags.ObjectType ? target.left as SpreadType : target);
}
// If both right sides are type parameters, then they must be identical for the spread types to be related.
// It also means that the left sides are either spread types or object types.
// if one left is object and the other is spread, that means the second has another type parameter. which isn't allowed
if (target.right.symbol !== source.right.symbol) {
return false;
}
if (source.left.flags & TypeFlags.Spread && target.left.flags & TypeFlags.Spread) {
// If the left sides are both spread types, then recursively check them.
return spreadTypeRelatedTo(source.left as SpreadType, target.left as SpreadType);
}
if (source.right.flags & TypeFlags.ObjectType) {
/// target.right is TypeParameter, skip source.right, but keep looking at target
return spreadTypeRelatedTo(source.left as SpreadType, target);
}
if (target.right.flags & TypeFlags.ObjectType) {
/// source.right is TypeParameter, skip target.right, but keep looking at source
return spreadTypeRelatedTo(source, target.left as SpreadType);
}
else {
// both rights are type parameters, so they must be identical
// and both lefts must be the same:
// if one left is object and the other is spread, that means the second has another type parameter. which isn't allowed
if (target.right.symbol !== source.right.symbol) {
return false;
}
if (source.left.flags & TypeFlags.Spread && target.left.flags & TypeFlags.Spread) {
return spreadTypeRelatedTo(source.left as SpreadType, target.left as SpreadType);
}
else if (source.left.flags & TypeFlags.ObjectType && target.left.flags & TypeFlags.ObjectType) {
return true; // let structural compatibility figure it out later
}
else {
// one side is a spread, so it must have more type parameters, which will not be matched by the other side
// return false immediately instead of descending to find this out.
return false;
}
}
// If the left sides are both object types, then isRelatedTo will check the structural compatibility next.
// Otherwise, one side has more type parameters than the other and the spread types are not related.
return !!(source.left.flags & TypeFlags.ObjectType && target.left.flags & TypeFlags.ObjectType);
}
function isIdenticalTo(source: Type, target: Type): Ternary {
@@ -6927,8 +6928,8 @@ namespace ts {
}
if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union ||
source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) {
if (result = eachTypeRelatedToSomeType(<TypeOperatorType>source, <TypeOperatorType>target, /*reportErrors*/ false)) {
if (result &= eachTypeRelatedToSomeType(<TypeOperatorType>target, <TypeOperatorType>source, /*reportErrors*/ false)) {
if (result = eachTypeRelatedToSomeType(<UnionOrIntersectionType>source, <UnionOrIntersectionType>target, /*reportErrors*/ false)) {
if (result &= eachTypeRelatedToSomeType(<UnionOrIntersectionType>target, <UnionOrIntersectionType>source, /*reportErrors*/ false)) {
return result;
}
}
@@ -6951,7 +6952,7 @@ namespace ts {
}
}
else if (type.flags & TypeFlags.UnionOrIntersection) {
for (const t of (<TypeOperatorType>type).types) {
for (const t of (<UnionOrIntersectionType>type).types) {
if (isKnownProperty(t, name)) {
return true;
}
@@ -6989,7 +6990,7 @@ namespace ts {
return false;
}
function eachTypeRelatedToSomeType(source: TypeOperatorType, target: TypeOperatorType, reportErrors: boolean): Ternary {
function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType, reportErrors: boolean): Ternary {
let result = Ternary.True;
const sourceTypes = source.types;
for (const sourceType of sourceTypes) {
@@ -7002,7 +7003,7 @@ namespace ts {
return result;
}
function typeRelatedToSomeType(source: Type, target: TypeOperatorType, reportErrors: boolean): Ternary {
function typeRelatedToSomeType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary {
const targetTypes = target.types;
if (target.flags & TypeFlags.Union && containsType(targetTypes, source)) {
return Ternary.True;
@@ -7017,7 +7018,7 @@ namespace ts {
return Ternary.False;
}
function typeRelatedToEachType(source: Type, target: TypeOperatorType, reportErrors: boolean): Ternary {
function typeRelatedToEachType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary {
let result = Ternary.True;
const targetTypes = target.types;
for (const targetType of targetTypes) {
@@ -7030,7 +7031,7 @@ namespace ts {
return result;
}
function someTypeRelatedToType(source: TypeOperatorType, target: Type, reportErrors: boolean): Ternary {
function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary {
const sourceTypes = source.types;
if (source.flags & TypeFlags.Union && containsType(sourceTypes, target)) {
return Ternary.True;
@@ -7045,7 +7046,7 @@ namespace ts {
return Ternary.False;
}
function eachTypeRelatedToType(source: TypeOperatorType, target: Type, reportErrors: boolean): Ternary {
function eachTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary {
let result = Ternary.True;
const sourceTypes = source.types;
for (const sourceType of sourceTypes) {
@@ -7990,10 +7991,10 @@ namespace ts {
return !!(type.flags & TypeFlags.TypeParameter ||
type.flags & TypeFlags.Reference && forEach((<TypeReference>type).typeArguments, couldContainTypeParameters) ||
type.flags & TypeFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) ||
type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(<TypeOperatorType>type));
type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(<UnionOrIntersectionType>type));
}
function couldUnionOrIntersectionContainTypeParameters(type: TypeOperatorType): boolean {
function couldUnionOrIntersectionContainTypeParameters(type: UnionOrIntersectionType): boolean {
if (type.couldContainTypeParameters === undefined) {
type.couldContainTypeParameters = forEach(type.types, couldContainTypeParameters);
}
@@ -8001,7 +8002,7 @@ namespace ts {
}
function isTypeParameterAtTopLevel(type: Type, typeParameter: TypeParameter): boolean {
return type === typeParameter || type.flags & TypeFlags.UnionOrIntersection && forEach((<TypeOperatorType>type).types, t => isTypeParameterAtTopLevel(t, typeParameter));
return type === typeParameter || type.flags & TypeFlags.UnionOrIntersection && forEach((<UnionOrIntersectionType>type).types, t => isTypeParameterAtTopLevel(t, typeParameter));
}
function inferTypes(context: InferenceContext, originalSource: Type, originalTarget: Type) {
@@ -8031,7 +8032,7 @@ namespace ts {
// Source and target are both unions or both intersections. If source and target
// are the same type, just relate each constituent type to itself.
if (source === target) {
for (const t of (<TypeOperatorType>source).types) {
for (const t of (<UnionOrIntersectionType>source).types) {
inferFromTypes(t, t);
}
return;
@@ -8043,14 +8044,14 @@ namespace ts {
// and string literals because the number and string types are not represented as unions
// of all their possible values.
let matchingTypes: Type[];
for (const t of (<TypeOperatorType>source).types) {
if (typeIdenticalToSomeType(t, (<TypeOperatorType>target).types)) {
for (const t of (<UnionOrIntersectionType>source).types) {
if (typeIdenticalToSomeType(t, (<UnionOrIntersectionType>target).types)) {
(matchingTypes || (matchingTypes = [])).push(t);
inferFromTypes(t, t);
}
else if (t.flags & (TypeFlags.NumberLiteral | TypeFlags.StringLiteral)) {
const b = getBaseTypeOfLiteralType(t);
if (typeIdenticalToSomeType(b, (<TypeOperatorType>target).types)) {
if (typeIdenticalToSomeType(b, (<UnionOrIntersectionType>target).types)) {
(matchingTypes || (matchingTypes = [])).push(t, b);
}
}
@@ -8059,8 +8060,8 @@ namespace ts {
// removing the identically matched constituents. For example, when inferring from
// 'string | string[]' to 'string | T' we reduce the types to 'string[]' and 'T'.
if (matchingTypes) {
source = removeTypesFromUnionOrIntersection(<TypeOperatorType>source, matchingTypes);
target = removeTypesFromUnionOrIntersection(<TypeOperatorType>target, matchingTypes);
source = removeTypesFromUnionOrIntersection(<UnionOrIntersectionType>source, matchingTypes);
target = removeTypesFromUnionOrIntersection(<UnionOrIntersectionType>target, matchingTypes);
}
}
if (target.flags & TypeFlags.TypeParameter) {
@@ -8107,7 +8108,7 @@ namespace ts {
}
}
else if (target.flags & TypeFlags.UnionOrIntersection) {
const targetTypes = (<TypeOperatorType>target).types;
const targetTypes = (<UnionOrIntersectionType>target).types;
let typeParameterCount = 0;
let typeParameter: TypeParameter;
// First infer to each type in union or intersection that isn't a type parameter
@@ -8131,7 +8132,7 @@ namespace ts {
}
else if (source.flags & TypeFlags.UnionOrIntersection) {
// Source is a union or intersection type, infer from each constituent type
const sourceTypes = (<TypeOperatorType>source).types;
const sourceTypes = (<UnionOrIntersectionType>source).types;
for (const sourceType of sourceTypes) {
inferFromTypes(sourceType, target);
}
@@ -8236,7 +8237,7 @@ namespace ts {
* Return a new union or intersection type computed by removing a given set of types
* from a given union or intersection type.
*/
function removeTypesFromUnionOrIntersection(type: TypeOperatorType, typesToRemove: Type[]) {
function removeTypesFromUnionOrIntersection(type: UnionOrIntersectionType, typesToRemove: Type[]) {
const reducedTypes: Type[] = [];
for (const t of type.types) {
if (!typeIdenticalToSomeType(t, typesToRemove)) {
@@ -8549,7 +8550,7 @@ namespace ts {
return getTypeFacts(constraint || emptyObjectType);
}
if (flags & TypeFlags.UnionOrIntersection) {
return getTypeFactsOfTypes((<TypeOperatorType>type).types);
return getTypeFactsOfTypes((<UnionOrIntersectionType>type).types);
}
return TypeFacts.All;
}
@@ -10632,13 +10633,6 @@ namespace ts {
type = checkExpressionForMutableLocation((<ShorthandPropertyAssignment>memberDecl).name, contextualMapper);
}
if (hasProperty(propertiesTable, member.name)) {
const existingPropType = getTypeOfSymbol(propertiesTable[member.name]);
if (!isTypeIdenticalTo(existingPropType, type)) {
error(memberDecl.name, Diagnostics.Cannot_change_type_of_property_0_from_1_to_2, member.name, typeToString(existingPropType), typeToString(type));
}
}
typeFlags |= type.flags;
const prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name);
if (inDestructuringPattern) {
@@ -10992,7 +10986,7 @@ namespace ts {
elemType = checkExpression(node.tagName);
}
if (elemType.flags & TypeFlags.Union) {
const types = (<TypeOperatorType>elemType).types;
const types = (<UnionOrIntersectionType>elemType).types;
return getUnionType(types.map(type => {
return getResolvedJsxType(node, type, elemClassType);
}), /*subtypeReduction*/ true);
@@ -13557,7 +13551,7 @@ namespace ts {
return true;
}
if (type.flags & TypeFlags.UnionOrIntersection) {
const types = (<TypeOperatorType>type).types;
const types = (<UnionOrIntersectionType>type).types;
for (const t of types) {
if (maybeTypeOfKind(t, kind)) {
return true;
@@ -13575,7 +13569,7 @@ namespace ts {
return true;
}
if (type.flags & TypeFlags.Union) {
const types = (<TypeOperatorType>type).types;
const types = (<UnionOrIntersectionType>type).types;
for (const t of types) {
if (!isTypeOfKind(t, kind)) {
return false;
@@ -13584,7 +13578,7 @@ namespace ts {
return true;
}
if (type.flags & TypeFlags.Intersection) {
const types = (<TypeOperatorType>type).types;
const types = (<UnionOrIntersectionType>type).types;
for (const t of types) {
if (isTypeOfKind(t, kind)) {
return true;
@@ -14980,9 +14974,11 @@ namespace ts {
forEach(node.members, checkSourceElement);
if (produceDiagnostics) {
const type = getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
checkIndexConstraints(type);
checkTypeForDuplicateIndexSignatures(node);
checkObjectTypeForDuplicateDeclarations(node);
if (type.flags & TypeFlags.ObjectType) {
checkIndexConstraints(type);
checkTypeForDuplicateIndexSignatures(node);
checkObjectTypeForDuplicateDeclarations(node);
}
}
}
@@ -20317,17 +20313,6 @@ namespace ts {
for (const prop of node.properties) {
if (prop.kind === SyntaxKind.SpreadElementExpression) {
const target = (prop as SpreadElementExpression).expression;
switch (target.kind) {
case SyntaxKind.Identifier:
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.NullKeyword:
break;
default:
grammarErrorOnNode(target, Diagnostics.Spread_properties_must_be_identifiers_property_accesses_or_object_literals);
}
continue;
}
const name = prop.name;

View File

@@ -1967,17 +1967,9 @@
"category": "Error",
"code": 2696
},
"Spread properties must be identifiers, property accesses, or object literals.": {
"category": "Error",
"code": 2697
},
"Cannot change type of property '{0}' from '{1}' to '{2}'.": {
"category": "Error",
"code": 2698
},
"Interface declaration cannot contain a spread property.": {
"category": "Error",
"code": 2699
"code": 2697
},
"Import declaration '{0}' is using private name '{1}'.": {

View File

@@ -1802,7 +1802,7 @@ namespace ts {
export interface JSDocRecordType extends JSDocType {
kind: SyntaxKind.JSDocRecordType;
literal: TypeLiteralNode;
literal: TypeLiteralNode;
}
export interface JSDocTypeReference extends JSDocType {
@@ -2536,7 +2536,7 @@ namespace ts {
instantiations?: Map<Type>; // Instantiations of generic type alias (undefined if non-generic)
mapper?: TypeMapper; // Type mapper for instantiation alias
referenced?: boolean; // True if alias symbol has been referenced as a value
referenced?: boolean; // True if alias symbol has been referenced as a value
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
leftSpread?: Symbol; // Left source for synthetic spread property
rightSpread?: Symbol; // Right source for synthetic spread property
hasNonUniformType?: boolean; // True if constituents have non-uniform types
@@ -2755,7 +2755,7 @@ namespace ts {
instantiations: Map<TypeReference>; // Generic instantiation cache
}
export interface UnionOrIntersectionType extends Type {
types: Type[]; // Constituent types
/* @internal */
resolvedProperties: SymbolTable; // Cache of resolved properties
@@ -2763,9 +2763,9 @@ namespace ts {
couldContainTypeParameters: boolean;
}
export interface UnionType extends UnionOrIntersectionType { }
export interface IntersectionType extends UnionOrIntersectionType { }
/* @internal */
export interface SpreadType extends Type {
@@ -2782,7 +2782,7 @@ namespace ts {
/* @internal */
// Resolved object, spread, union, or intersection type
// Resolved object, spread, union, or intersection type
export interface ResolvedType extends ObjectType, UnionOrIntersectionType {
members: SymbolTable; // Properties by name
properties: Symbol[]; // Properties
callSignatures: Signature[]; // Call signatures of type

View File

@@ -458,7 +458,7 @@ namespace ts.FindAllReferences {
return [localParentType.symbol];
}
else if (localParentType.flags & TypeFlags.UnionOrIntersection) {
return getSymbolsForClassAndInterfaceComponents(<TypeOperatorType>localParentType);
return getSymbolsForClassAndInterfaceComponents(<UnionOrIntersectionType>localParentType);
}
}
}
@@ -630,13 +630,13 @@ namespace ts.FindAllReferences {
}
}
function getSymbolsForClassAndInterfaceComponents(type: TypeOperatorType, result: Symbol[] = []): Symbol[] {
function getSymbolsForClassAndInterfaceComponents(type: UnionOrIntersectionType, result: Symbol[] = []): Symbol[] {
for (const componentType of type.types) {
if (componentType.symbol && componentType.symbol.getFlags() & (SymbolFlags.Class | SymbolFlags.Interface)) {
result.push(componentType.symbol);
}
if (componentType.getFlags() & TypeFlags.UnionOrIntersection) {
getSymbolsForClassAndInterfaceComponents(<TypeOperatorType>componentType, result);
getSymbolsForClassAndInterfaceComponents(<UnionOrIntersectionType>componentType, result);
}
}
return result;