Allow booleans in spread types

Special-case types produced by `bool && expr` with the type `false | T`.
This spreads `Partial<T>` instead of `false | T`.
This commit is contained in:
Nathan Shively-Sanders 2017-09-13 14:04:14 -07:00
parent 2a70bf5158
commit 60f1d4573d

View File

@ -7832,12 +7832,25 @@ namespace ts {
return left;
}
if (left.flags & TypeFlags.Union) {
return mapType(left, t => getSpreadType(t, right));
// if the union is `false | T` make all the properties of T optional
const wl = getPartialTypeFromFalseUnion(left as UnionType);
if (wl) {
left = wl;
}
else {
return mapType(left, t => getSpreadType(t, right));
}
}
if (right.flags & TypeFlags.Union) {
return mapType(right, t => getSpreadType(left, t));
const wr = getPartialTypeFromFalseUnion(right as UnionType);
if (wr) {
right = wr;
}
else {
return mapType(right, t => getSpreadType(left, t));
}
}
if (right.flags & TypeFlags.NonPrimitive) {
if (right.flags & (TypeFlags.NonPrimitive | TypeFlags.BooleanLike)) {
return emptyObjectType;
}
@ -7908,6 +7921,29 @@ namespace ts {
return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent));
}
function getPartialTypeFromFalseUnion(type: UnionType): Type | undefined {
if (type.types.length === 2) {
const i = type.types.indexOf(falseType);
if (i > -1) {
const members = createSymbolTable();
const other = type.types[i === 0 ? 1 : 0];
for (const prop of getPropertiesOfType(other)) {
if (prop.flags & SymbolFlags.Optional) {
members.set(prop.escapedName, prop);
}
else {
const result = createSymbol(prop.flags | SymbolFlags.Optional, prop.escapedName);
result.type = getUnionType([getTypeOfSymbol(prop), undefinedType]);
result.declarations = prop.declarations;
result.syntheticOrigin = prop;
members.set(prop.escapedName, result);
}
}
return createAnonymousType(undefined, members, emptyArray, emptyArray, getIndexInfoOfType(other, IndexKind.String), getIndexInfoOfType(other, IndexKind.Number));
}
}
}
function createLiteralType(flags: TypeFlags, value: string | number, symbol: Symbol) {
const type = <LiteralType>createType(flags);
type.symbol = symbol;
@ -13749,7 +13785,7 @@ namespace ts {
}
function isValidSpreadType(type: Type): boolean {
return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined | TypeFlags.NonPrimitive) ||
return !!(type.flags & (TypeFlags.Any | TypeFlags.Nullable | TypeFlags.NonPrimitive | TypeFlags.BooleanLike) ||
type.flags & TypeFlags.Object && !isGenericMappedType(type) ||
type.flags & TypeFlags.UnionOrIntersection && !forEach((<UnionOrIntersectionType>type).types, t => !isValidSpreadType(t)));
}