Merge pull request #28234 from Microsoft/genericSpread

Generic spread expressions in object literals
This commit is contained in:
Anders Hejlsberg
2018-10-31 12:52:16 -07:00
committed by GitHub
15 changed files with 582 additions and 319 deletions

View File

@@ -4639,7 +4639,7 @@ namespace ts {
let type: Type | undefined;
if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
if (declaration.dotDotDotToken) {
if (parentType.flags & TypeFlags.Unknown || !isValidSpreadType(parentType)) {
if (parentType.flags & TypeFlags.Unknown || !isValidSpreadType(parentType) || isGenericObjectType(parentType)) {
error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types);
return errorType;
}
@@ -9842,6 +9842,10 @@ namespace ts {
return symbol ? getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) : undefined;
}
function isNonGenericObjectType(type: Type) {
return !!(type.flags & TypeFlags.Object) && !isGenericMappedType(type);
}
/**
* Since the source of spread types are object literals, which are not binary,
* this function should be called in a left folding style, with left = previous result of getSpreadType
@@ -9870,6 +9874,23 @@ namespace ts {
return left;
}
if (isGenericObjectType(left) || isGenericObjectType(right)) {
if (isEmptyObjectType(left)) {
return right;
}
// When the left type is an intersection, we may need to merge the last constituent of the
// intersection with the right type. For example when the left type is 'T & { a: string }'
// and the right type is '{ b: string }' we produce 'T & { a: string, b: string }'.
if (left.flags & TypeFlags.Intersection) {
const types = (<IntersectionType>left).types;
const lastLeft = types[types.length - 1];
if (isNonGenericObjectType(lastLeft) && isNonGenericObjectType(right)) {
return getIntersectionType(concatenate(types.slice(0, types.length - 1), [getSpreadType(lastLeft, right, symbol, typeFlags, objectFlags)]));
}
}
return getIntersectionType([left, right]);
}
const members = createSymbolTable();
const skippedPrivateMembers = createUnderscoreEscapedMap<boolean>();
let stringIndexInfo: IndexInfo | undefined;
@@ -17700,9 +17721,8 @@ namespace ts {
}
function isValidSpreadType(type: Type): boolean {
return !!(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.NonPrimitive) ||
return !!(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.NonPrimitive | TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) ||
getFalsyFlags(type) & TypeFlags.DefinitelyFalsy && isValidSpreadType(removeDefinitelyFalsyTypes(type)) ||
type.flags & TypeFlags.Object && !isGenericMappedType(type) ||
type.flags & TypeFlags.UnionOrIntersection && every((<UnionOrIntersectionType>type).types, isValidSpreadType));
}