@@ -7822,6 +7822,7 @@ namespace ts {
78227822 * and right = the new element to be spread.
78237823 */
78247824 function getSpreadType(left: Type, right: Type): Type {
7825+ let truthyRight: Type;
78257826 if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) {
78267827 return anyType;
78277828 }
@@ -7832,25 +7833,18 @@ namespace ts {
78327833 return left;
78337834 }
78347835 if (left.flags & TypeFlags.Union) {
7835- // if the union is `false | T` make all the properties of T optional
7836- const wl = getPartialTypeFromFalsyUnion(left as UnionType);
7837- if (wl) {
7838- left = wl;
7839- }
7840- else {
7841- return mapType(left, t => getSpreadType(t, right));
7842- }
7836+ return mapType(left, t => getSpreadType(t, right));
78437837 }
78447838 if (right.flags & TypeFlags.Union) {
7845- const wr = getPartialTypeFromFalsyUnion (right as UnionType);
7846- if (wr ) {
7847- right = wr ;
7839+ truthyRight = getTruthyTypeFromFalsyUnion (right as UnionType);
7840+ if (!truthyRight || truthyRight.flags & TypeFlags.Union ) {
7841+ return mapType( right, t => getSpreadType(left, t)) ;
78487842 }
78497843 else {
7850- return mapType( right, t => getSpreadType(left, t)) ;
7844+ right = truthyRight ;
78517845 }
78527846 }
7853- if (right.flags & (TypeFlags.NonPrimitive | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike)) {
7847+ if (right.flags & (TypeFlags.NonPrimitive | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.EnumLike )) {
78547848 return emptyObjectType;
78557849 }
78567850
@@ -7875,9 +7869,10 @@ namespace ts {
78757869 skippedPrivateMembers.set(rightProp.escapedName, true);
78767870 }
78777871 else if (!isClassMethod(rightProp) && !isSetterWithoutGetter) {
7878- members.set(rightProp.escapedName, getNonReadonlySymbol (rightProp));
7872+ members.set(rightProp.escapedName, getSymbolOfSpreadProperty (rightProp, !!truthyRight ));
78797873 }
78807874 }
7875+
78817876 for (const leftProp of getPropertiesOfType(left)) {
78827877 if (leftProp.flags & SymbolFlags.SetAccessor && !(leftProp.flags & SymbolFlags.GetAccessor)
78837878 || skippedPrivateMembers.has(leftProp.escapedName)
@@ -7899,19 +7894,22 @@ namespace ts {
78997894 }
79007895 }
79017896 else {
7902- members.set(leftProp.escapedName, getNonReadonlySymbol (leftProp));
7897+ members.set(leftProp.escapedName, getSymbolOfSpreadProperty (leftProp, /*makeOptional*/ false ));
79037898 }
79047899 }
79057900 return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
79067901 }
79077902
7908- function getNonReadonlySymbol (prop: Symbol) {
7909- if (!isReadonlySymbol(prop)) {
7903+ function getSymbolOfSpreadProperty (prop: Symbol, makeOptional: boolean ) {
7904+ if (!isReadonlySymbol(prop) && (!makeOptional || prop.flags & SymbolFlags.Optional) ) {
79107905 return prop;
79117906 }
7912- const flags = SymbolFlags.Property | (prop.flags & SymbolFlags.Optional);
7907+ const flags = SymbolFlags.Property | (makeOptional ? SymbolFlags.Optional : prop.flags & SymbolFlags.Optional);
79137908 const result = createSymbol(flags, prop.escapedName);
79147909 result.type = getTypeOfSymbol(prop);
7910+ if (makeOptional) {
7911+ result.type = getUnionType([result.type, undefinedType]);
7912+ }
79157913 result.declarations = prop.declarations;
79167914 result.syntheticOrigin = prop;
79177915 return result;
@@ -7921,25 +7919,10 @@ namespace ts {
79217919 return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent));
79227920 }
79237921
7924- function getPartialTypeFromFalsyUnion(type: UnionType): Type | undefined {
7925- if (type.types.length === 2) {
7926- const truthy = removeDefinitelyFalsyTypes(type);
7927- if (truthy !== type) {
7928- const members = createSymbolTable();
7929- for (const prop of getPropertiesOfType(truthy)) {
7930- if (prop.flags & SymbolFlags.Optional) {
7931- members.set(prop.escapedName, prop);
7932- }
7933- else {
7934- const result = createSymbol(prop.flags | SymbolFlags.Optional, prop.escapedName);
7935- result.type = getUnionType([getTypeOfSymbol(prop), undefinedType]);
7936- result.declarations = prop.declarations;
7937- result.syntheticOrigin = prop;
7938- members.set(prop.escapedName, result);
7939- }
7940- }
7941- return createAnonymousType(undefined, members, emptyArray, emptyArray, getIndexInfoOfType(truthy, IndexKind.String), getIndexInfoOfType(truthy, IndexKind.Number));
7942- }
7922+ function getTruthyTypeFromFalsyUnion(type: UnionType): Type | undefined {
7923+ const truthy = removeDefinitelyFalsyTypes(type);
7924+ if (truthy !== type) {
7925+ return truthy;
79437926 }
79447927 }
79457928
@@ -13784,7 +13767,8 @@ namespace ts {
1378413767 }
1378513768
1378613769 function isValidSpreadType(type: Type): boolean {
13787- return !!(type.flags & (TypeFlags.Any | TypeFlags.PossiblyFalsy | TypeFlags.NonPrimitive) ||
13770+ return !!(type.flags & (TypeFlags.Any | TypeFlags.NonPrimitive) ||
13771+ getFalsyFlags(type) & TypeFlags.DefinitelyFalsy && isValidSpreadType(removeDefinitelyFalsyTypes(type)) ||
1378813772 type.flags & TypeFlags.Object && !isGenericMappedType(type) ||
1378913773 type.flags & TypeFlags.UnionOrIntersection && !forEach((<UnionOrIntersectionType>type).types, t => !isValidSpreadType(t)));
1379013774 }
0 commit comments