diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a09b63d46fd0a..da675db601c90 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -126,6 +126,7 @@ namespace ts { const tupleTypes: GenericType[] = []; const unionTypes = createMap(); const intersectionTypes = createMap(); + const spreadTypes = createMap(); const stringLiteralTypes = createMap(); const numericLiteralTypes = createMap(); const indexedAccessTypes = createMap(); @@ -2346,6 +2347,9 @@ namespace ts { else if (type.flags & TypeFlags.UnionOrIntersection) { writeUnionOrIntersectionType(type, nextFlags); } + else if (type.flags & TypeFlags.Spread) { + writeSpreadType(type as SpreadType); + } else if (getObjectFlags(type) & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) { writeAnonymousType(type, nextFlags); } @@ -2461,6 +2465,28 @@ namespace ts { } } + function writeSpreadType(type: SpreadType, nested?: boolean) { + if (nested && type.left === emptyObjectType) { + writeType(type.right, TypeFormatFlags.None); + } + else { + writer.writeKeyword("spread"); + writePunctuation(writer, SyntaxKind.OpenParenToken); + if (type.left !== emptyObjectType) { + if (type.left.flags & TypeFlags.Spread) { + writeSpreadType(type.left as SpreadType, /*nested*/ true); + } + else { + writeType(type.left, TypeFormatFlags.None); + } + writePunctuation(writer, SyntaxKind.CommaToken); + writeSpace(writer); + } + writeType(type.right, TypeFormatFlags.None); + writePunctuation(writer, SyntaxKind.CloseParenToken); + } + } + function writeAnonymousType(type: ObjectType, flags: TypeFormatFlags) { const symbol = type.symbol; if (symbol) { @@ -4868,6 +4894,10 @@ namespace ts { } } + function getApparentTypeOfSpread(type: SpreadType) { + return getApparentType(type.right); + } + function getApparentTypeOfIntersectionType(type: IntersectionType) { return type.resolvedIndexType || (type.resolvedApparentType = getTypeWithThisArgument(type, type)); } @@ -4878,7 +4908,9 @@ namespace ts { * type itself. Note that the apparent type of a union type is the union type itself. */ function getApparentType(type: Type): Type { - const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type; + const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : + type.flags & TypeFlags.Spread ? getApparentTypeOfSpread(type as SpreadType) : + type; return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t) : t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : @@ -6084,6 +6116,16 @@ namespace ts { return links.resolvedType; } + function getTypeFromSpreadTypeNode(node: SpreadTypeNode): Type { + const links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = getSpreadType( + node.right ? getTypeFromTypeNode(node.left) : emptyObjectType, + getTypeFromTypeNode(node.right || node.left)); + } + return links.resolvedType; + } + function getIndexTypeForGenericType(type: TypeVariable | UnionOrIntersectionType) { if (!type.resolvedIndexType) { type.resolvedIndexType = createType(TypeFlags.Index); @@ -6297,14 +6339,35 @@ namespace ts { } /** - * 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 - * and right = the new element to be spread. + * Since spread types are binary and object literals are not, + * checkObjectLiteral calls getSpreadType in a left-folding way. + * If a nested spread type literal is not left-deep, getSpreadType will transform it to left-deep form. + * + * If getSpreadType returns a spread type, the following properties hold: + * 1. Left-deep: spread.left is always another spread type (the recursive case) + or an object (the terminal case) + * Callers of getSpreadType should use emptyObjectType as the initial object + if the left-most type is not an object. + * 2. spread.right is never a spread type, but one of + TypeParameter, Object, Intersection, Index or IndexedAccess + * 3. When recurring down a spread type chain, you will never encounter two object types in a row. */ function getSpreadType(left: Type, right: Type): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } + const id = getTypeListId([left, right]); + if (spreadTypes.has(id)) { + return spreadTypes.get(id); + } + // flatten intersections to objects if all member types are objects + if (left.flags & TypeFlags.Intersection) { + left = resolveObjectIntersection(left as IntersectionType); + } + if (right.flags & TypeFlags.Intersection) { + right = resolveObjectIntersection(right as IntersectionType); + } + // filter null and undefined left = filterType(left, t => !(t.flags & TypeFlags.Nullable)); if (left.flags & TypeFlags.Never) { return right; @@ -6313,16 +6376,94 @@ namespace ts { if (right.flags & TypeFlags.Never) { return left; } + // distribute union over spread if (left.flags & TypeFlags.Union) { return mapType(left, t => getSpreadType(t, right)); } if (right.flags & TypeFlags.Union) { return mapType(right, t => getSpreadType(left, t)); } - if (right.flags & TypeFlags.NonPrimitive) { + + // filter primitives (this is reported as an error elsewhere) + if (left.flags & TypeFlags.Primitive && (right.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive))) { return emptyObjectType; } + if (left.flags & TypeFlags.Primitive) { + return right; + } + if (right.flags & TypeFlags.Primitive) { + return left; + } + + if (!(left.flags & (TypeFlags.Spread | TypeFlags.Object))) { + // put an emptyObjectType terminator on the left + left = getSpreadType(emptyObjectType, left); + } + const simplified = simplifySpreadType(left, right); + if (simplified) { + return simplified; + } + + if (right.flags & TypeFlags.Object && left.flags & TypeFlags.Object) { + return createSpreadType(left, right); + } + const spread = createType(TypeFlags.Spread) as SpreadType + spread.left = left as SpreadType | ResolvedType; + spread.right = right as TypeParameter | IntersectionType | IndexType | IndexedAccessType | ResolvedType; + spreadTypes.set(id, spread); + return spread; + } + function resolveObjectIntersection(intersection: IntersectionType): IntersectionType | ResolvedType { + if (find(intersection.types, t => !(t.flags & TypeFlags.Object))) { + return intersection; + } + const members = createMap(); + for (const property of getPropertiesOfType(intersection)) { + members.set(property.name, property); + } + const stringIndex = getIndexInfoOfType(intersection, IndexKind.String); + const numberIndex = getIndexInfoOfType(intersection, IndexKind.Number); + return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndex, numberIndex); + } + + /** + * Simplify spread types: + * 1. Collapse duplicates: T ... T => T + * 2. Collapse adjacent object types: { x } ... { y } ... T => { x, y } ... T + * 3. Associativity: (T ... U) .. V => T ... (U ... V) + * + * (2) and (3) are important for creating a spread type that obeys the invariants described + * in getSpreadType. + */ + function simplifySpreadType(left: Type, right: Type) { + if (left.flags & TypeFlags.Spread && + right.flags & TypeFlags.TypeParameter && + (left as SpreadType).right.flags & TypeFlags.TypeParameter && + right.symbol === (left as SpreadType).right.symbol) { + // ... T ... T => ... T + return left; + } + if (left.flags & TypeFlags.Spread && + right.flags & TypeFlags.Object && + (left as SpreadType).right.flags & TypeFlags.Object) { + // simplify two adjacent object types: T ... { x } ... { y } => T ... { x, y } + const simplified = getSpreadType(right, (left as SpreadType).right); + return getSpreadType((left as SpreadType).left, simplified); + } + if (right.flags & TypeFlags.Spread) { + // spread is right associated and associativity applies, so + // (T ... U) ... V => T ... (U ... V) + const rspread = right as SpreadType; + if (rspread.left === emptyObjectType) { + // ... U ... ({} ... T) => ... U ... T + return getSpreadType(left, rspread.right); + } + return getSpreadType(getSpreadType(left, rspread.left), rspread.right); + } + } + + function createSpreadType(left: Type, right: Type) { const members = createMap(); const skippedPrivateMembers = createMap(); let stringIndexInfo: IndexInfo; @@ -6513,6 +6654,8 @@ namespace ts { return getTypeFromUnionTypeNode(node); case SyntaxKind.IntersectionType: return getTypeFromIntersectionTypeNode(node); + case SyntaxKind.SpreadType: + return getTypeFromSpreadTypeNode(node as SpreadTypeNode); case SyntaxKind.ParenthesizedType: case SyntaxKind.JSDocNullableType: case SyntaxKind.JSDocNonNullableType: @@ -6888,6 +7031,10 @@ namespace ts { if (type.flags & TypeFlags.Intersection) { return getIntersectionType(instantiateTypes((type).types, mapper), type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); } + if (type.flags & TypeFlags.Spread) { + const spread = type as SpreadType; + return getSpreadType(instantiateType(spread.left, mapper), instantiateType(spread.right, mapper)); + } if (type.flags & TypeFlags.Index) { return getIndexType(instantiateType((type).type, mapper)); } @@ -7514,6 +7661,20 @@ namespace ts { } } } + else if (source.flags & TypeFlags.Spread && target.flags & TypeFlags.Spread) { + if (!spreadTypeRelatedTo(source as SpreadType, target as SpreadType, /*atRightEdge*/ true)) { + 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; + } + } if (source.flags & TypeFlags.TypeParameter) { // A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X. @@ -7525,6 +7686,12 @@ namespace ts { return result; } } + else if (target.flags & TypeFlags.Spread) { + // T is assignable to ...T + if (source === (target as SpreadType).right && (target as SpreadType).left === emptyObjectType) { + return Ternary.True; + } + } else { let constraint = getConstraintOfTypeParameter(source); // A type parameter with no constraint is not related to the non-primitive object type. @@ -7589,6 +7756,32 @@ namespace ts { return Ternary.False; } + function spreadTypeRelatedTo(source: SpreadType, target: SpreadType, atRightEdge?: boolean): boolean { + // 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.Object || target.right.flags & TypeFlags.Object) { + return atRightEdge && + spreadTypeRelatedTo(source.right.flags & TypeFlags.Object ? source.left as SpreadType : source, + target.right.flags & TypeFlags.Object ? target.left as SpreadType : target); + } + // If both right sides are type parameters, intersections, index types or indexed access types, + // 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 !== source.right) { + 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 the left sides are both object types, then we should be at the end and both should be emptyObjectType. + // If not, we can't know what properties might have been overwritten, so fail. + return source.left === emptyObjectType && target.left === emptyObjectType; + } + function isIdenticalTo(source: Type, target: Type): Ternary { let result: Ternary; if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) { @@ -11733,7 +11926,7 @@ namespace ts { typeFlags = 0; } const type = checkExpression((memberDecl as SpreadAssignment).expression); - if (!isValidSpreadType(type)) { + if (type.flags & (TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.BooleanLike | TypeFlags.EnumLike | TypeFlags.ESSymbol)) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } @@ -20238,8 +20431,13 @@ namespace ts { } else if (symbol.flags & SymbolFlags.Transient) { if ((symbol as SymbolLinks).leftSpread) { - const links = symbol as SymbolLinks; - return [links.leftSpread, links.rightSpread]; + const symbols = []; + while ((symbol as SymbolLinks).leftSpread) { + symbols.push((symbol as SymbolLinks).rightSpread); + symbol = (symbol as SymbolLinks).leftSpread; + } + symbols.push(symbol); + return symbols; } if ((symbol as SymbolLinks).mappedTypeOrigin) { return getRootSymbols((symbol as SymbolLinks).mappedTypeOrigin); @@ -21499,6 +21697,7 @@ namespace ts { checkGrammarHeritageClause(heritageClause); } } + return false; } diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 46df4fed6896d..d9cda8132eb91 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -413,6 +413,8 @@ namespace ts { return emitUnionType(type); case SyntaxKind.IntersectionType: return emitIntersectionType(type); + case SyntaxKind.SpreadType: + return emitSpreadType(type as SpreadTypeNode); case SyntaxKind.ParenthesizedType: return emitParenType(type); case SyntaxKind.TypeOperator: @@ -1175,6 +1177,15 @@ namespace ts { writeLine(); } + function emitSpreadType(type: SpreadTypeNode) { + write("spread("); + emitType(type.left); + write(",") + emitType(type.right); + write(")"); + writeLine(); + } + function emitVariableDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration) { // If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted // so there is no check needed to see if declaration is visible diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c795cab14a34e..9767f97420ff3 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -76,6 +76,9 @@ namespace ts { visitNode(cbNode, (node).objectAssignmentInitializer); case SyntaxKind.SpreadAssignment: return visitNode(cbNode, (node).expression); + case SyntaxKind.SpreadType: + return visitNode(cbNode, (node as SpreadTypeNode).left) || + visitNode(cbNode, (node as SpreadTypeNode).right); case SyntaxKind.Parameter: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: @@ -2611,6 +2614,26 @@ namespace ts { return type; } + function parseSpreadType(): TypeNode { + const node = createNode(SyntaxKind.SpreadType) as SpreadTypeNode; + parseExpected(SyntaxKind.SpreadKeyword); + parseExpected(SyntaxKind.OpenParenToken); + node.left = parseType(); + if (parseOptional(SyntaxKind.CommaToken)) { + node.right = parseType(); + } + parseExpected(SyntaxKind.CloseParenToken); + return finishNode(node); + } + + function parseSpreadTypeOrHigher() { + switch (token()) { + case SyntaxKind.SpreadKeyword: + return parseSpreadType(); + } + return parseArrayTypeOrHigher(); + } + function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword) { const node = createNode(SyntaxKind.TypeOperator); parseExpected(operator); @@ -2624,7 +2647,7 @@ namespace ts { case SyntaxKind.KeyOfKeyword: return parseTypeOperator(SyntaxKind.KeyOfKeyword); } - return parseArrayTypeOrHigher(); + return parseSpreadTypeOrHigher(); } function parseUnionOrIntersectionType(kind: SyntaxKind, parseConstituentType: () => TypeNode, operator: SyntaxKind): TypeNode { diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 52c75a370050f..3647836c81b64 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -108,6 +108,7 @@ namespace ts { "global": SyntaxKind.GlobalKeyword, "return": SyntaxKind.ReturnKeyword, "set": SyntaxKind.SetKeyword, + "spread": SyntaxKind.SpreadKeyword, "static": SyntaxKind.StaticKeyword, "string": SyntaxKind.StringKeyword, "super": SyntaxKind.SuperKeyword, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8b49af402cf6c..b7ea3d0c92ea8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -188,6 +188,7 @@ GetKeyword, IsKeyword, KeyOfKeyword, + SpreadKeyword, ModuleKeyword, NamespaceKeyword, NeverKeyword, @@ -235,6 +236,7 @@ TupleType, UnionType, IntersectionType, + SpreadType, ParenthesizedType, ThisType, TypeOperator, @@ -905,6 +907,12 @@ kind: SyntaxKind.IntersectionType; } + export interface SpreadTypeNode extends TypeNode { + kind: SyntaxKind.SpreadType; + left: TypeNode; + right?: TypeNode; + } + export interface ParenthesizedTypeNode extends TypeNode { kind: SyntaxKind.ParenthesizedType; type: TypeNode; @@ -2491,12 +2499,6 @@ CannotBeNamed } - /* @internal */ - export const enum SyntheticSymbolKind { - UnionOrIntersection, - Spread - } - export const enum TypePredicateKind { This, Identifier @@ -2622,7 +2624,7 @@ Merged = 0x02000000, // Merged symbol (created during program binding) Transient = 0x04000000, // Transient symbol (created during type check) Prototype = 0x08000000, // Prototype property (no source representation) - SyntheticProperty = 0x10000000, // Property in union or intersection type + SyntheticProperty = 0x10000000, // Property in union, intersection or spread type Optional = 0x20000000, // Optional property ExportStar = 0x40000000, // Export * declaration @@ -2815,6 +2817,7 @@ /* @internal */ ContainsAnyFunctionType = 1 << 23, // Type is or contains object literal type NonPrimitive = 1 << 24, // intrinsic object type + Spread = 1 << 25, // Spread type /* @internal */ Nullable = Undefined | Null, @@ -2832,13 +2835,13 @@ BooleanLike = Boolean | BooleanLiteral, EnumLike = Enum | EnumLiteral, UnionOrIntersection = Union | Intersection, - StructuredType = Object | Union | Intersection, + StructuredType = Object | Union | Intersection | Spread, StructuredOrTypeVariable = StructuredType | TypeParameter | Index | IndexedAccess, TypeVariable = TypeParameter | IndexedAccess, // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never - Narrowable = Any | StructuredType | TypeParameter | Index | IndexedAccess | StringLike | NumberLike | BooleanLike | ESSymbol | NonPrimitive, + Narrowable = Any | StructuredType | TypeParameter | Index | IndexedAccess | StringLike | NumberLike | BooleanLike | ESSymbol | NonPrimitive | Spread, NotUnionOrUnit = Any | ESSymbol | Object | NonPrimitive, /* @internal */ RequiresWidening = ContainsWideningType | ContainsObjectLiteral, @@ -2969,6 +2972,13 @@ export type StructuredType = ObjectType | UnionType | IntersectionType; + /* @internal */ + export interface SpreadType extends Type { + left: SpreadType | ResolvedType; + // Note: probably should just make this to be Type now + right: TypeParameter | IntersectionType | IndexType | IndexedAccessType | ResolvedType; + } + /* @internal */ // An instantiated anonymous type has a target and a mapper export interface AnonymousType extends ObjectType { @@ -2992,7 +3002,7 @@ } /* @internal */ - // Resolved object, 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 diff --git a/src/lib/es2015.core.d.ts b/src/lib/es2015.core.d.ts index 356512ecf5848..5d46a11369c52 100644 --- a/src/lib/es2015.core.d.ts +++ b/src/lib/es2015.core.d.ts @@ -278,7 +278,7 @@ interface ObjectConstructor { * @param target The target object to copy to. * @param source The source object from which to copy properties. */ - assign(target: T, source: U): T & U; + assign(target: T, source: U): spread(T, U); /** * Copy the values of all of the enumerable own properties from one or more source objects to a @@ -287,7 +287,7 @@ interface ObjectConstructor { * @param source1 The first source object from which to copy properties. * @param source2 The second source object from which to copy properties. */ - assign(target: T, source1: U, source2: V): T & U & V; + assign(target: T, source1: U, source2: V): spread(spread(T, U), V); /** * Copy the values of all of the enumerable own properties from one or more source objects to a @@ -297,7 +297,7 @@ interface ObjectConstructor { * @param source2 The second source object from which to copy properties. * @param source3 The third source object from which to copy properties. */ - assign(target: T, source1: U, source2: V, source3: W): T & U & V & W; + assign(target: T, source1: U, source2: V, source3: W): spread(spread(spread(T, U), V), W); /** * Copy the values of all of the enumerable own properties from one or more source objects to a diff --git a/tests/baselines/reference/interfaceSpread.errors.txt b/tests/baselines/reference/interfaceSpread.errors.txt deleted file mode 100644 index c6acc63391278..0000000000000 --- a/tests/baselines/reference/interfaceSpread.errors.txt +++ /dev/null @@ -1,21 +0,0 @@ -tests/cases/conformance/types/spread/interfaceSpread.ts(2,5): error TS2698: Interface declaration cannot contain a spread property. -tests/cases/conformance/types/spread/interfaceSpread.ts(7,10): error TS2339: Property 'jam' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. -tests/cases/conformance/types/spread/interfaceSpread.ts(8,10): error TS2339: Property 'peanutButter' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. - - -==== tests/cases/conformance/types/spread/interfaceSpread.ts (3 errors) ==== - interface Congealed { - ...T - ~~~~ -!!! error TS2698: Interface declaration cannot contain a spread property. - ...U - } - - let sandwich: Congealed<{jam: number }, { peanutButter: number }>; - sandwich.jam; - ~~~ -!!! error TS2339: Property 'jam' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. - sandwich.peanutButter; - ~~~~~~~~~~~~ -!!! error TS2339: Property 'peanutButter' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. - \ No newline at end of file diff --git a/tests/baselines/reference/interfaceSpread.js b/tests/baselines/reference/interfaceSpread.js deleted file mode 100644 index 89f2531436667..0000000000000 --- a/tests/baselines/reference/interfaceSpread.js +++ /dev/null @@ -1,15 +0,0 @@ -//// [interfaceSpread.ts] -interface Congealed { - ...T - ...U -} - -let sandwich: Congealed<{jam: number }, { peanutButter: number }>; -sandwich.jam; -sandwich.peanutButter; - - -//// [interfaceSpread.js] -var sandwich; -sandwich.jam; -sandwich.peanutButter; diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index 2bc3b9e11bd8f..8c7766ce6e750 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -35,7 +35,10 @@ let getter: { a: number, c: number } = { ...op, c: 7 } getter.a = 12; -// functions result in { } +// null, undefined, object and functions result in { } +let spreadNull = { ...null }; +let spreadUndefined = { ...undefined }; +let spreadNonPrimitive = { ...{}}; let spreadFunc = { ...(function () { }) }; // any results in any @@ -78,8 +81,24 @@ let computedAfter: { a: number, b: string, "at the end": number } = // shortcut syntax let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } -// non primitive -let spreadNonPrimitive = { ...{}}; + +// generics +function f(t: T, u: U): spread(spread(T, U), { id: string }) { + return { ...t, ...u, id: 'id' }; +} + +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +let overlap: { id: string, a: number, b: string } = + f({ a: 1 }, { a: 2, b: 'extra' }) +let overlapConflict: { id:string, a: string } = + f({ a: 1 }, { a: 'mismatch' }) +let overwriteId: { id: string, a: number, c: number, d: string } = + f({ a: 1, id: true }, { c: 1, d: 'no' }) + +class D { m() { }; q = 2; } +let classesAreWrong: spread(spread({ id: string }, C), D) = + f(new C(), new D()) //// [objectSpread.js] @@ -112,7 +131,10 @@ var propertyNested = { a: __assign({}, o) }; var op = { get a() { return 6; } }; var getter = __assign({}, op, { c: 7 }); getter.a = 12; -// functions result in { } +// null, undefined, object and functions result in { } +var spreadNull = __assign({}, null); +var spreadUndefined = __assign({}, undefined); +var spreadNonPrimitive = __assign({}, {}); var spreadFunc = __assign({}, (function () { })); // any results in any var anything; @@ -149,6 +171,21 @@ var computedAfter = __assign({}, o, (_c = { b: 'yeah' }, _c['at the end'] = 14, // shortcut syntax var a = 12; var shortCutted = __assign({}, o, { a: a }); -// non primitive -var spreadNonPrimitive = __assign({}, {}); +// generics +function f(t, u) { + return __assign({}, t, u, { id: 'id' }); +} +var exclusive = f({ a: 1, b: 'yes' }, { c: 'no', d: false }); +var overlap = f({ a: 1 }, { a: 2, b: 'extra' }); +var overlapConflict = f({ a: 1 }, { a: 'mismatch' }); +var overwriteId = f({ a: 1, id: true }, { c: 1, d: 'no' }); +var D = (function () { + function D() { + this.q = 2; + } + D.prototype.m = function () { }; + ; + return D; +}()); +var classesAreWrong = f(new C(), new D()); var _a, _b, _c; diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 1ec2520e166f2..0d440485fd966 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -165,70 +165,80 @@ getter.a = 12; >getter : Symbol(getter, Decl(objectSpread.ts, 32, 3)) >a : Symbol(a, Decl(objectSpread.ts, 32, 13)) -// functions result in { } +// null, undefined, object and functions result in { } +let spreadNull = { ...null }; +>spreadNull : Symbol(spreadNull, Decl(objectSpread.ts, 37, 3)) + +let spreadUndefined = { ...undefined }; +>spreadUndefined : Symbol(spreadUndefined, Decl(objectSpread.ts, 38, 3)) +>undefined : Symbol(undefined) + +let spreadNonPrimitive = { ...{}}; +>spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 39, 3)) + let spreadFunc = { ...(function () { }) }; ->spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 37, 3)) +>spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 40, 3)) // any results in any let anything: any; ->anything : Symbol(anything, Decl(objectSpread.ts, 40, 3)) +>anything : Symbol(anything, Decl(objectSpread.ts, 43, 3)) let spreadAny = { ...anything }; ->spreadAny : Symbol(spreadAny, Decl(objectSpread.ts, 41, 3)) ->anything : Symbol(anything, Decl(objectSpread.ts, 40, 3)) +>spreadAny : Symbol(spreadAny, Decl(objectSpread.ts, 44, 3)) +>anything : Symbol(anything, Decl(objectSpread.ts, 43, 3)) // methods are not enumerable class C { p = 1; m() { } } ->C : Symbol(C, Decl(objectSpread.ts, 41, 32)) ->p : Symbol(C.p, Decl(objectSpread.ts, 44, 9)) ->m : Symbol(C.m, Decl(objectSpread.ts, 44, 16)) +>C : Symbol(C, Decl(objectSpread.ts, 44, 32)) +>p : Symbol(C.p, Decl(objectSpread.ts, 47, 9)) +>m : Symbol(C.m, Decl(objectSpread.ts, 47, 16)) let c: C = new C() ->c : Symbol(c, Decl(objectSpread.ts, 45, 3)) ->C : Symbol(C, Decl(objectSpread.ts, 41, 32)) ->C : Symbol(C, Decl(objectSpread.ts, 41, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 48, 3)) +>C : Symbol(C, Decl(objectSpread.ts, 44, 32)) +>C : Symbol(C, Decl(objectSpread.ts, 44, 32)) let spreadC: { p: number } = { ...c } ->spreadC : Symbol(spreadC, Decl(objectSpread.ts, 46, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 46, 14)) ->c : Symbol(c, Decl(objectSpread.ts, 45, 3)) +>spreadC : Symbol(spreadC, Decl(objectSpread.ts, 49, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 49, 14)) +>c : Symbol(c, Decl(objectSpread.ts, 48, 3)) // own methods are enumerable let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; ->cplus : Symbol(cplus, Decl(objectSpread.ts, 49, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 49, 12)) ->plus : Symbol(plus, Decl(objectSpread.ts, 49, 23)) ->c : Symbol(c, Decl(objectSpread.ts, 45, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 49, 48)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 52, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 52, 12)) +>plus : Symbol(plus, Decl(objectSpread.ts, 52, 23)) +>c : Symbol(c, Decl(objectSpread.ts, 48, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 52, 48)) cplus.plus(); ->cplus.plus : Symbol(plus, Decl(objectSpread.ts, 49, 23)) ->cplus : Symbol(cplus, Decl(objectSpread.ts, 49, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 49, 23)) +>cplus.plus : Symbol(plus, Decl(objectSpread.ts, 52, 23)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 52, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 52, 23)) // new field's type conflicting with existing field is OK let changeTypeAfter: { a: string, b: string } = ->changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 53, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 53, 22)) ->b : Symbol(b, Decl(objectSpread.ts, 53, 33)) +>changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 56, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 56, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 56, 33)) { ...o, a: 'wrong type?' } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 54, 11)) +>a : Symbol(a, Decl(objectSpread.ts, 57, 11)) let changeTypeBefore: { a: number, b: string } = ->changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 55, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 55, 23)) ->b : Symbol(b, Decl(objectSpread.ts, 55, 34)) +>changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 58, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 58, 23)) +>b : Symbol(b, Decl(objectSpread.ts, 58, 34)) { a: 'wrong type?', ...o }; ->a : Symbol(a, Decl(objectSpread.ts, 56, 5)) +>a : Symbol(a, Decl(objectSpread.ts, 59, 5)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) let changeTypeBoth: { a: string, b: number } = ->changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 57, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 57, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 57, 32)) +>changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 60, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 60, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 60, 32)) { ...o, ...swap }; >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) @@ -236,87 +246,169 @@ let changeTypeBoth: { a: string, b: number } = // optional let definiteBoolean: { sn: boolean }; ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 61, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 61, 22)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 64, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 64, 22)) let definiteString: { sn: string }; ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 62, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 62, 21)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 65, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 65, 21)) let optionalString: { sn?: string }; ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 63, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 63, 21)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 66, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 66, 21)) let optionalNumber: { sn?: number }; ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 64, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 64, 21)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 67, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 67, 21)) let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; ->optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 65, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 65, 25)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 61, 3)) ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 62, 3)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 64, 3)) +>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 68, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 68, 25)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 64, 3)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 65, 3)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 67, 3)) let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; ->optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 66, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 66, 30)) ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 61, 3)) ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 62, 3)) ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 63, 3)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 64, 3)) +>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 69, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 69, 30)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 64, 3)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 65, 3)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 66, 3)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 67, 3)) let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; ->allOptional : Symbol(allOptional, Decl(objectSpread.ts, 67, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 67, 18)) ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 63, 3)) ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 64, 3)) +>allOptional : Symbol(allOptional, Decl(objectSpread.ts, 70, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 70, 18)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 66, 3)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 67, 3)) // computed property let computedFirst: { a: number, b: string, "before everything": number } = ->computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 70, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 70, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 70, 31)) +>computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 73, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 73, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 73, 31)) { ['before everything']: 12, ...o, b: 'yes' } ->'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 71, 5)) +>'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 74, 5)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 71, 38)) +>b : Symbol(b, Decl(objectSpread.ts, 74, 38)) let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = ->computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 72, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 72, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 72, 32)) ->c : Symbol(c, Decl(objectSpread.ts, 72, 43)) +>computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 75, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 75, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 75, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 75, 43)) { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 73, 11)) ->b : Symbol(b, Decl(objectSpread.ts, 73, 34)) +>'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 76, 11)) +>b : Symbol(b, Decl(objectSpread.ts, 76, 34)) >o2 : Symbol(o2, Decl(objectSpread.ts, 1, 3)) let computedAfter: { a: number, b: string, "at the end": number } = ->computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 74, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 74, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 74, 31)) +>computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 77, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 77, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 77, 31)) { ...o, b: 'yeah', ['at the end']: 14 } >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->b : Symbol(b, Decl(objectSpread.ts, 75, 11)) ->'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 75, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 78, 11)) +>'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 78, 22)) // shortcut syntax let a = 12; ->a : Symbol(a, Decl(objectSpread.ts, 77, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 80, 3)) let shortCutted: { a: number, b: string } = { ...o, a } ->shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 78, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 78, 18)) ->b : Symbol(b, Decl(objectSpread.ts, 78, 29)) +>shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 81, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 81, 18)) +>b : Symbol(b, Decl(objectSpread.ts, 81, 29)) >o : Symbol(o, Decl(objectSpread.ts, 0, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 78, 51)) - -// non primitive -let spreadNonPrimitive = { ...{}}; ->spreadNonPrimitive : Symbol(spreadNonPrimitive, Decl(objectSpread.ts, 80, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 81, 51)) + +// generics +function f(t: T, u: U): spread(spread(T, U), { id: string }) { +>f : Symbol(f, Decl(objectSpread.ts, 81, 55)) +>T : Symbol(T, Decl(objectSpread.ts, 84, 11)) +>U : Symbol(U, Decl(objectSpread.ts, 84, 13)) +>t : Symbol(t, Decl(objectSpread.ts, 84, 17)) +>T : Symbol(T, Decl(objectSpread.ts, 84, 11)) +>u : Symbol(u, Decl(objectSpread.ts, 84, 22)) +>U : Symbol(U, Decl(objectSpread.ts, 84, 13)) +>T : Symbol(T, Decl(objectSpread.ts, 84, 11)) +>U : Symbol(U, Decl(objectSpread.ts, 84, 13)) +>id : Symbol(id, Decl(objectSpread.ts, 84, 52)) + + return { ...t, ...u, id: 'id' }; +>t : Symbol(t, Decl(objectSpread.ts, 84, 17)) +>u : Symbol(u, Decl(objectSpread.ts, 84, 22)) +>id : Symbol(id, Decl(objectSpread.ts, 85, 24)) +} + +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = +>exclusive : Symbol(exclusive, Decl(objectSpread.ts, 88, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 88, 16)) +>a : Symbol(a, Decl(objectSpread.ts, 88, 28)) +>b : Symbol(b, Decl(objectSpread.ts, 88, 39)) +>c : Symbol(c, Decl(objectSpread.ts, 88, 50)) +>d : Symbol(d, Decl(objectSpread.ts, 88, 61)) + + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +>f : Symbol(f, Decl(objectSpread.ts, 81, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 89, 7)) +>b : Symbol(b, Decl(objectSpread.ts, 89, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 89, 27)) +>d : Symbol(d, Decl(objectSpread.ts, 89, 36)) + +let overlap: { id: string, a: number, b: string } = +>overlap : Symbol(overlap, Decl(objectSpread.ts, 90, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 90, 14)) +>a : Symbol(a, Decl(objectSpread.ts, 90, 26)) +>b : Symbol(b, Decl(objectSpread.ts, 90, 37)) + + f({ a: 1 }, { a: 2, b: 'extra' }) +>f : Symbol(f, Decl(objectSpread.ts, 81, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 91, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 91, 17)) +>b : Symbol(b, Decl(objectSpread.ts, 91, 23)) + +let overlapConflict: { id:string, a: string } = +>overlapConflict : Symbol(overlapConflict, Decl(objectSpread.ts, 92, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 92, 22)) +>a : Symbol(a, Decl(objectSpread.ts, 92, 33)) + + f({ a: 1 }, { a: 'mismatch' }) +>f : Symbol(f, Decl(objectSpread.ts, 81, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 93, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 93, 17)) + +let overwriteId: { id: string, a: number, c: number, d: string } = +>overwriteId : Symbol(overwriteId, Decl(objectSpread.ts, 94, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 94, 18)) +>a : Symbol(a, Decl(objectSpread.ts, 94, 30)) +>c : Symbol(c, Decl(objectSpread.ts, 94, 41)) +>d : Symbol(d, Decl(objectSpread.ts, 94, 52)) + + f({ a: 1, id: true }, { c: 1, d: 'no' }) +>f : Symbol(f, Decl(objectSpread.ts, 81, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 95, 7)) +>id : Symbol(id, Decl(objectSpread.ts, 95, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 95, 27)) +>d : Symbol(d, Decl(objectSpread.ts, 95, 33)) + +class D { m() { }; q = 2; } +>D : Symbol(D, Decl(objectSpread.ts, 95, 44)) +>m : Symbol(D.m, Decl(objectSpread.ts, 97, 9)) +>q : Symbol(D.q, Decl(objectSpread.ts, 97, 18)) + +let classesAreWrong: spread(spread({ id: string }, C), D) = +>classesAreWrong : Symbol(classesAreWrong, Decl(objectSpread.ts, 98, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 98, 36)) +>C : Symbol(C, Decl(objectSpread.ts, 44, 32)) +>D : Symbol(D, Decl(objectSpread.ts, 95, 44)) + + f(new C(), new D()) +>f : Symbol(f, Decl(objectSpread.ts, 81, 55)) +>C : Symbol(C, Decl(objectSpread.ts, 44, 32)) +>D : Symbol(D, Decl(objectSpread.ts, 95, 44)) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 950dab43465c7..66514e316c7c0 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -223,7 +223,23 @@ getter.a = 12; >a : number >12 : 12 -// functions result in { } +// null, undefined, object and functions result in { } +let spreadNull = { ...null }; +>spreadNull : {} +>{ ...null } : {} +>null : null + +let spreadUndefined = { ...undefined }; +>spreadUndefined : {} +>{ ...undefined } : {} +>undefined : undefined + +let spreadNonPrimitive = { ...{}}; +>spreadNonPrimitive : spread(object) +>{ ...{}} : spread(object) +>{} : object +>{} : {} + let spreadFunc = { ...(function () { }) }; >spreadFunc : {} >{ ...(function () { }) } : {} @@ -407,10 +423,120 @@ let shortCutted: { a: number, b: string } = { ...o, a } >o : { a: number; b: string; } >a : number -// non primitive -let spreadNonPrimitive = { ...{}}; ->spreadNonPrimitive : {} ->{ ...{}} : {} ->{} : object ->{} : {} +// generics +function f(t: T, u: U): spread(spread(T, U), { id: string }) { +>f : (t: T, u: U) => spread(spread(T, U), { id: string; }) +>T : T +>U : U +>t : T +>T : T +>u : U +>U : U +>T : T +>U : U +>id : string + + return { ...t, ...u, id: 'id' }; +>{ ...t, ...u, id: 'id' } : spread(spread(T, U), { id: string; }) +>t : T +>u : U +>id : string +>'id' : "id" +} + +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = +>exclusive : { id: string; a: number; b: string; c: string; d: boolean; } +>id : string +>a : number +>b : string +>c : string +>d : boolean + + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +>f({ a: 1, b: 'yes' }, { c: 'no', d: false }) : { id: string; c: string; d: boolean; a: number; b: string; } +>f : (t: T, u: U) => spread(spread(T, U), { id: string; }) +>{ a: 1, b: 'yes' } : { a: number; b: string; } +>a : number +>1 : 1 +>b : string +>'yes' : "yes" +>{ c: 'no', d: false } : { c: string; d: false; } +>c : string +>'no' : "no" +>d : boolean +>false : false + +let overlap: { id: string, a: number, b: string } = +>overlap : { id: string; a: number; b: string; } +>id : string +>a : number +>b : string + + f({ a: 1 }, { a: 2, b: 'extra' }) +>f({ a: 1 }, { a: 2, b: 'extra' }) : { id: string; a: number; b: string; } +>f : (t: T, u: U) => spread(spread(T, U), { id: string; }) +>{ a: 1 } : { a: number; } +>a : number +>1 : 1 +>{ a: 2, b: 'extra' } : { a: number; b: string; } +>a : number +>2 : 2 +>b : string +>'extra' : "extra" + +let overlapConflict: { id:string, a: string } = +>overlapConflict : { id: string; a: string; } +>id : string +>a : string + + f({ a: 1 }, { a: 'mismatch' }) +>f({ a: 1 }, { a: 'mismatch' }) : { id: string; a: string; } +>f : (t: T, u: U) => spread(spread(T, U), { id: string; }) +>{ a: 1 } : { a: number; } +>a : number +>1 : 1 +>{ a: 'mismatch' } : { a: string; } +>a : string +>'mismatch' : "mismatch" + +let overwriteId: { id: string, a: number, c: number, d: string } = +>overwriteId : { id: string; a: number; c: number; d: string; } +>id : string +>a : number +>c : number +>d : string + + f({ a: 1, id: true }, { c: 1, d: 'no' }) +>f({ a: 1, id: true }, { c: 1, d: 'no' }) : { id: string; c: number; d: string; a: number; } +>f : (t: T, u: U) => spread(spread(T, U), { id: string; }) +>{ a: 1, id: true } : { a: number; id: true; } +>a : number +>1 : 1 +>id : boolean +>true : true +>{ c: 1, d: 'no' } : { c: number; d: string; } +>c : number +>1 : 1 +>d : string +>'no' : "no" + +class D { m() { }; q = 2; } +>D : D +>m : () => void +>q : number +>2 : 2 + +let classesAreWrong: spread(spread({ id: string }, C), D) = +>classesAreWrong : { q: number; p: number; id: string; } +>id : string +>C : C +>D : D + + f(new C(), new D()) +>f(new C(), new D()) : { id: string; q: number; p: number; } +>f : (t: T, u: U) => spread(spread(T, U), { id: string; }) +>new C() : C +>C : typeof C +>new D() : D +>D : typeof D diff --git a/tests/baselines/reference/objectSpreadGeneric.errors.txt b/tests/baselines/reference/objectSpreadGeneric.errors.txt new file mode 100644 index 0000000000000..4e0d30d896f4a --- /dev/null +++ b/tests/baselines/reference/objectSpreadGeneric.errors.txt @@ -0,0 +1,148 @@ +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(9,5): error TS2322: Type 'spread(U)' is not assignable to type 'U'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(10,11): error TS2322: Type 'spread(spread(T, U), V)' is not assignable to type 'spread(spread(V, U), T)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(11,11): error TS2322: Type 'spread(spread(T, U), V)' is not assignable to type 'spread(spread(U, T), V)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(12,11): error TS2322: Type 'spread(spread(T, U), V)' is not assignable to type 'spread(U, V)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(13,11): error TS2322: Type 'spread(spread(T, U), V)' is not assignable to type 'spread(T, V)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(14,11): error TS2322: Type 'spread(spread(T, U), V)' is not assignable to type 'spread(T, U)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(16,11): error TS90010: Type 'spread(spread({ first: string; }, T), U)' is not assignable to type 'spread(spread({ first: string; }, T), U)'. Two different types with this name exist, but they are unrelated. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(19,11): error TS2322: Type '{}' is not assignable to type 'spread(T, U)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(26,11): error TS2322: Type 'spread(spread({ sn?: boolean; }, T), { sn?: string | number; })' is not assignable to type 'spread(T, { sn?: string | number | boolean; })'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(32,11): error TS90010: Type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; })' is not assignable to type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; })'. Two different types with this name exist, but they are unrelated. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(34,11): error TS2322: Type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; })' is not assignable to type 'spread(spread({ first: string; second: string; }, T), { third: string; })'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(36,11): error TS90010: Type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; secondsecond: string; })' is not assignable to type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; secondsecond: string; })'. Two different types with this name exist, but they are unrelated. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(38,11): error TS2322: Type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; secondsecond: string; })' is not assignable to type 'spread(spread({ first: string; second: string; secondsecond: string; third: string; }, T), U)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(42,11): error TS2322: Type 'spread(spread(spread(spread({ firrrrrrst: string; }, T), { second: string; }), U), { third: string; })' is not assignable to type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; })'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(44,11): error TS2322: Type 'spread(spread(spread(spread({ first: string; }, T), { ssssssssecond: string; }), U), { third: string; })' is not assignable to type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; })'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(46,11): error TS2322: Type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { thirrrrrrrd: string; })' is not assignable to type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; })'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(57,5): error TS2322: Type 'spread(keyof U)' is not assignable to type 'spread(keyof T)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(58,5): error TS2322: Type 'spread(keyof T)' is not assignable to type 'spread(keyof U)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(61,5): error TS2322: Type 'spread(K)' is not assignable to type 'spread(keyof T)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(62,5): error TS2322: Type 'spread(keyof T)' is not assignable to type 'spread(K)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(63,5): error TS2322: Type 'spread(J)' is not assignable to type 'spread(keyof U)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(64,5): error TS2322: Type 'spread(keyof U)' is not assignable to type 'spread(J)'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(70,5): error TS2322: Type 'spread(U[J])' is not assignable to type 'spread(T[K])'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(71,5): error TS2322: Type 'spread(T[K])' is not assignable to type 'spread(U[J])'. + + +==== tests/cases/conformance/types/spread/objectSpreadGeneric.ts (24 errors) ==== + function f(t: T, u: U, v: V): void { + let o: spread(spread(T, U), V); + let uus: spread(U, U); + let us: spread(U); + const same: spread(spread(T, U), V) = o; // ok + uus = us; // ok, multiple spreads are equivalent to a single one + us = uus; // ok, multiple spreads are equivalent to a single one + us = u; // ok, type has at least all the properties of the spread + u = us; // error, might be missing a ton of stuff + ~ +!!! error TS2322: Type 'spread(U)' is not assignable to type 'U'. + const reversed: spread(spread(V, U), T) = o; // error, reversed + ~~~~~~~~ +!!! error TS2322: Type 'spread(spread(T, U), V)' is not assignable to type 'spread(spread(V, U), T)'. + const reversed2: spread(spread(U, T), V) = o; // error, U and T are still reversed + ~~~~~~~~~ +!!! error TS2322: Type 'spread(spread(T, U), V)' is not assignable to type 'spread(spread(U, T), V)'. + const missingT: spread(U, V) = o; // error, missing T + ~~~~~~~~ +!!! error TS2322: Type 'spread(spread(T, U), V)' is not assignable to type 'spread(U, V)'. + const missingU: spread(T, V) = o; // error, missing U + ~~~~~~~~ +!!! error TS2322: Type 'spread(spread(T, U), V)' is not assignable to type 'spread(T, V)'. + const missingV: spread(T, U) = o; // error, missing V + ~~~~~~~~ +!!! error TS2322: Type 'spread(spread(T, U), V)' is not assignable to type 'spread(T, U)'. + const atEnd: spread(spread(T, U), { second: string }) = { ...t, ...u, second: 'foo' }; // ok + const atBeginning: spread(spread({ first: string }, T), U) = { first: 'foo', ...t, ...u }; // error, not assignable + ~~~~~~~~~~~ +!!! error TS90010: Type 'spread(spread({ first: string; }, T), U)' is not assignable to type 'spread(spread({ first: string; }, T), U)'. Two different types with this name exist, but they are unrelated. + + const emptyTarget: { } = { ...t, ...u } // ok + const emptySource: spread(T, U) = { }; // error, {} is not assignable to U (or T) + ~~~~~~~~~~~ +!!! error TS2322: Type '{}' is not assignable to type 'spread(T, U)'. + + // error, { sn?: boolean } ...T ... { sn?: number | string } is not assignable to + // T ... { sn?: number | string | boolean } + let optionalNumber: { sn?: number }; + let optionalString: { sn?: string }; + let optionalBoolean: { sn?: boolean }; + const unionCutoff: spread(T, { sn?: number | string | boolean }) = + ~~~~~~~~~~~ +!!! error TS2322: Type 'spread(spread({ sn?: boolean; }, T), { sn?: string | number; })' is not assignable to type 'spread(T, { sn?: string | number | boolean; })'. + { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } + unionCutoff.sn; // ok + const optionalCutoff = { ...t, ...optionalNumber }; // ok + optionalCutoff.sn; // ok + + const interspersed: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string }) = + ~~~~~~~~~~~~ +!!! error TS90010: Type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; })' is not assignable to type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; })'. Two different types with this name exist, but they are unrelated. + { first: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable + const interspersedMissingU: spread(spread({ first: string, second: string }, T), { third: string }) = + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; })' is not assignable to type 'spread(spread({ first: string; second: string; }, T), { third: string; })'. + { first: '1', ...t, second: '2', ...u, third: '3' }; // error, 'U' is missing + const interspersedOrder1: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string , secondsecond: string }) = + ~~~~~~~~~~~~~~~~~~ +!!! error TS90010: Type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; secondsecond: string; })' is not assignable to type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; secondsecond: string; })'. Two different types with this name exist, but they are unrelated. + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable + const interspersedOrder2: spread(spread({ first: string, second: string, secondsecond: string, third: string }, T), U) = + ~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; secondsecond: string; })' is not assignable to type 'spread(spread({ first: string; second: string; secondsecond: string; third: string; }, T), U)'. + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable + + + const mismatchFirst: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string }) = + ~~~~~~~~~~~~~ +!!! error TS2322: Type 'spread(spread(spread(spread({ firrrrrrst: string; }, T), { second: string; }), U), { third: string; })' is not assignable to type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; })'. + { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable + const mismatchSecond: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string }) = + ~~~~~~~~~~~~~~ +!!! error TS2322: Type 'spread(spread(spread(spread({ first: string; }, T), { ssssssssecond: string; }), U), { third: string; })' is not assignable to type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; })'. + { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, not assignable + const mismatchLast: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string }) = + ~~~~~~~~~~~~ +!!! error TS2322: Type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { thirrrrrrrd: string; })' is not assignable to type 'spread(spread(spread(spread({ first: string; }, T), { second: string; }), U), { third: string; })'. + { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, not assignable + } + + function indexAccessedTest(t: T, u: U, key1: K, key2: J) { + let k1: spread(keyof T); + let k2: spread(keyof U); + let k3: spread(K); + let k4: spread(J); + k1 = k1; // ok + k2 = k2; // ok + k1 = k2; // error + ~~ +!!! error TS2322: Type 'spread(keyof U)' is not assignable to type 'spread(keyof T)'. + k2 = k1; // error + ~~ +!!! error TS2322: Type 'spread(keyof T)' is not assignable to type 'spread(keyof U)'. + k3 = k3; // ok + k4 = k4; // ok + k1 = k3; // error + ~~ +!!! error TS2322: Type 'spread(K)' is not assignable to type 'spread(keyof T)'. + k3 = k1; // error + ~~ +!!! error TS2322: Type 'spread(keyof T)' is not assignable to type 'spread(K)'. + k2 = k4; // error + ~~ +!!! error TS2322: Type 'spread(J)' is not assignable to type 'spread(keyof U)'. + k4 = k2; // error + ~~ +!!! error TS2322: Type 'spread(keyof U)' is not assignable to type 'spread(J)'. + + let i1: spread(T[K]); + let i2: spread(U[J]); + i1 = i1; // ok + i2 = i2; // ok + i1 = i2; // error + ~~ +!!! error TS2322: Type 'spread(U[J])' is not assignable to type 'spread(T[K])'. + i2 = i1; // error + ~~ +!!! error TS2322: Type 'spread(T[K])' is not assignable to type 'spread(U[J])'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadGeneric.js b/tests/baselines/reference/objectSpreadGeneric.js new file mode 100644 index 0000000000000..0681486e99a11 --- /dev/null +++ b/tests/baselines/reference/objectSpreadGeneric.js @@ -0,0 +1,141 @@ +//// [objectSpreadGeneric.ts] +function f(t: T, u: U, v: V): void { + let o: spread(spread(T, U), V); + let uus: spread(U, U); + let us: spread(U); + const same: spread(spread(T, U), V) = o; // ok + uus = us; // ok, multiple spreads are equivalent to a single one + us = uus; // ok, multiple spreads are equivalent to a single one + us = u; // ok, type has at least all the properties of the spread + u = us; // error, might be missing a ton of stuff + const reversed: spread(spread(V, U), T) = o; // error, reversed + const reversed2: spread(spread(U, T), V) = o; // error, U and T are still reversed + const missingT: spread(U, V) = o; // error, missing T + const missingU: spread(T, V) = o; // error, missing U + const missingV: spread(T, U) = o; // error, missing V + const atEnd: spread(spread(T, U), { second: string }) = { ...t, ...u, second: 'foo' }; // ok + const atBeginning: spread(spread({ first: string }, T), U) = { first: 'foo', ...t, ...u }; // error, not assignable + + const emptyTarget: { } = { ...t, ...u } // ok + const emptySource: spread(T, U) = { }; // error, {} is not assignable to U (or T) + + // error, { sn?: boolean } ...T ... { sn?: number | string } is not assignable to + // T ... { sn?: number | string | boolean } + let optionalNumber: { sn?: number }; + let optionalString: { sn?: string }; + let optionalBoolean: { sn?: boolean }; + const unionCutoff: spread(T, { sn?: number | string | boolean }) = + { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } + unionCutoff.sn; // ok + const optionalCutoff = { ...t, ...optionalNumber }; // ok + optionalCutoff.sn; // ok + + const interspersed: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string }) = + { first: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable + const interspersedMissingU: spread(spread({ first: string, second: string }, T), { third: string }) = + { first: '1', ...t, second: '2', ...u, third: '3' }; // error, 'U' is missing + const interspersedOrder1: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string , secondsecond: string }) = + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable + const interspersedOrder2: spread(spread({ first: string, second: string, secondsecond: string, third: string }, T), U) = + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable + + + const mismatchFirst: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string }) = + { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable + const mismatchSecond: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string }) = + { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, not assignable + const mismatchLast: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string }) = + { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, not assignable +} + +function indexAccessedTest(t: T, u: U, key1: K, key2: J) { + let k1: spread(keyof T); + let k2: spread(keyof U); + let k3: spread(K); + let k4: spread(J); + k1 = k1; // ok + k2 = k2; // ok + k1 = k2; // error + k2 = k1; // error + k3 = k3; // ok + k4 = k4; // ok + k1 = k3; // error + k3 = k1; // error + k2 = k4; // error + k4 = k2; // error + + let i1: spread(T[K]); + let i2: spread(U[J]); + i1 = i1; // ok + i2 = i2; // ok + i1 = i2; // error + i2 = i1; // error +} + + +//// [objectSpreadGeneric.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +function f(t, u, v) { + var o; + var uus; + var us; + var same = o; // ok + uus = us; // ok, multiple spreads are equivalent to a single one + us = uus; // ok, multiple spreads are equivalent to a single one + us = u; // ok, type has at least all the properties of the spread + u = us; // error, might be missing a ton of stuff + var reversed = o; // error, reversed + var reversed2 = o; // error, U and T are still reversed + var missingT = o; // error, missing T + var missingU = o; // error, missing U + var missingV = o; // error, missing V + var atEnd = __assign({}, t, u, { second: 'foo' }); // ok + var atBeginning = __assign({ first: 'foo' }, t, u); // error, not assignable + var emptyTarget = __assign({}, t, u); // ok + var emptySource = {}; // error, {} is not assignable to U (or T) + // error, { sn?: boolean } ...T ... { sn?: number | string } is not assignable to + // T ... { sn?: number | string | boolean } + var optionalNumber; + var optionalString; + var optionalBoolean; + var unionCutoff = __assign({}, optionalBoolean, t, optionalString, optionalNumber); + unionCutoff.sn; // ok + var optionalCutoff = __assign({}, t, optionalNumber); // ok + optionalCutoff.sn; // ok + var interspersed = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3' }); // error, not assignable + var interspersedMissingU = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3' }); // error, 'U' is missing + var interspersedOrder1 = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3', secondsecond: 'false' }); // error, not assignable + var interspersedOrder2 = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3', secondsecond: 'false' }); // error, not assignable + var mismatchFirst = __assign({ firrrrrrst: '1' }, t, { second: '2' }, u, { third: '3' }); // error, not assignable + var mismatchSecond = __assign({ first: '1' }, t, { ssssssssecond: '2' }, u, { third: '3' }); // error, not assignable + var mismatchLast = __assign({ first: '1' }, t, { second: '2' }, u, { thirrrrrrrd: '3' }); // error, not assignable +} +function indexAccessedTest(t, u, key1, key2) { + var k1; + var k2; + var k3; + var k4; + k1 = k1; // ok + k2 = k2; // ok + k1 = k2; // error + k2 = k1; // error + k3 = k3; // ok + k4 = k4; // ok + k1 = k3; // error + k3 = k1; // error + k2 = k4; // error + k4 = k2; // error + var i1; + var i2; + i1 = i1; // ok + i2 = i2; // ok + i1 = i2; // error + i2 = i1; // error +} diff --git a/tests/baselines/reference/objectSpreadIndexSignature.js b/tests/baselines/reference/objectSpreadIndexSignature.js index 22e92e6a844bf..8975016479a5b 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.js +++ b/tests/baselines/reference/objectSpreadIndexSignature.js @@ -1,4 +1,12 @@ //// [objectSpreadIndexSignature.ts] +class C { + a: number; + c: boolean; +} +// index signatures are not allowed in object literals with spread types +let c: spread(C, { b: string, c?: string, [n: number]: string }); +let n: number = c.a; +let s: string = c[12]; interface Indexed { [n: string]: number; a: number; @@ -9,28 +17,36 @@ interface Indexed2 { } let indexed: Indexed; let indexed2: Indexed2; -let i = { ...indexed, b: 11 }; +let i: spread(Indexed, { b: number }); // only indexed has indexer, so i[101]: any i[101]; -let ii = { ...indexed, ...indexed2 }; +let ii: spread(spread(Indexed, Indexed2), { b: boolean, d: number }); // both have indexer, so i[1001]: number | boolean -ii[1001]; +let nb: number | boolean = ii[1001]; + +function f(t: T) { + let i: spread(T, { [n: number]: string }); +} //// [objectSpreadIndexSignature.js] -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; +var C = (function () { + function C() { } - return t; -}; + return C; +}()); +// index signatures are not allowed in object literals with spread types +var c; +var n = c.a; +var s = c[12]; var indexed; var indexed2; -var i = __assign({}, indexed, { b: 11 }); +var i; // only indexed has indexer, so i[101]: any i[101]; -var ii = __assign({}, indexed, indexed2); +var ii; // both have indexer, so i[1001]: number | boolean -ii[1001]; +var nb = ii[1001]; +function f(t) { + var i; +} diff --git a/tests/baselines/reference/objectSpreadIndexSignature.symbols b/tests/baselines/reference/objectSpreadIndexSignature.symbols index cd64b15719699..4c3c4479ad271 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.symbols +++ b/tests/baselines/reference/objectSpreadIndexSignature.symbols @@ -1,45 +1,87 @@ === tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts === +class C { +>C : Symbol(C, Decl(objectSpreadIndexSignature.ts, 0, 0)) + + a: number; +>a : Symbol(C.a, Decl(objectSpreadIndexSignature.ts, 0, 9)) + + c: boolean; +>c : Symbol(C.c, Decl(objectSpreadIndexSignature.ts, 1, 14)) +} +// index signatures are not allowed in object literals with spread types +let c: spread(C, { b: string, c?: string, [n: number]: string }); +>c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 5, 3)) +>C : Symbol(C, Decl(objectSpreadIndexSignature.ts, 0, 0)) +>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 5, 18)) +>c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 5, 29)) +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 5, 43)) + +let n: number = c.a; +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 6, 3)) +>c.a : Symbol(C.a, Decl(objectSpreadIndexSignature.ts, 0, 9)) +>c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 5, 3)) +>a : Symbol(C.a, Decl(objectSpreadIndexSignature.ts, 0, 9)) + +let s: string = c[12]; +>s : Symbol(s, Decl(objectSpreadIndexSignature.ts, 7, 3)) +>c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 5, 3)) + interface Indexed { ->Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 0, 0)) +>Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 7, 22)) [n: string]: number; ->n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 1, 5)) +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 9, 5)) a: number; ->a : Symbol(Indexed.a, Decl(objectSpreadIndexSignature.ts, 1, 24)) +>a : Symbol(Indexed.a, Decl(objectSpreadIndexSignature.ts, 9, 24)) } interface Indexed2 { ->Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 3, 1)) +>Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 11, 1)) [n: string]: boolean; ->n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 5, 5)) +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 13, 5)) c: boolean; ->c : Symbol(Indexed2.c, Decl(objectSpreadIndexSignature.ts, 5, 25)) +>c : Symbol(Indexed2.c, Decl(objectSpreadIndexSignature.ts, 13, 25)) } let indexed: Indexed; ->indexed : Symbol(indexed, Decl(objectSpreadIndexSignature.ts, 8, 3)) ->Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 0, 0)) +>indexed : Symbol(indexed, Decl(objectSpreadIndexSignature.ts, 16, 3)) +>Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 7, 22)) let indexed2: Indexed2; ->indexed2 : Symbol(indexed2, Decl(objectSpreadIndexSignature.ts, 9, 3)) ->Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 3, 1)) +>indexed2 : Symbol(indexed2, Decl(objectSpreadIndexSignature.ts, 17, 3)) +>Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 11, 1)) -let i = { ...indexed, b: 11 }; ->i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 10, 3)) ->indexed : Symbol(indexed, Decl(objectSpreadIndexSignature.ts, 8, 3)) ->b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 10, 21)) +let i: spread(Indexed, { b: number }); +>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 18, 3)) +>Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 7, 22)) +>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 18, 24)) // only indexed has indexer, so i[101]: any i[101]; ->i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 10, 3)) +>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 18, 3)) -let ii = { ...indexed, ...indexed2 }; ->ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 13, 3)) ->indexed : Symbol(indexed, Decl(objectSpreadIndexSignature.ts, 8, 3)) ->indexed2 : Symbol(indexed2, Decl(objectSpreadIndexSignature.ts, 9, 3)) +let ii: spread(spread(Indexed, Indexed2), { b: boolean, d: number }); +>ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 21, 3)) +>Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 7, 22)) +>Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 11, 1)) +>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 21, 43)) +>d : Symbol(d, Decl(objectSpreadIndexSignature.ts, 21, 55)) // both have indexer, so i[1001]: number | boolean -ii[1001]; ->ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 13, 3)) +let nb: number | boolean = ii[1001]; +>nb : Symbol(nb, Decl(objectSpreadIndexSignature.ts, 23, 3)) +>ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 21, 3)) + +function f(t: T) { +>f : Symbol(f, Decl(objectSpreadIndexSignature.ts, 23, 36)) +>T : Symbol(T, Decl(objectSpreadIndexSignature.ts, 25, 11)) +>t : Symbol(t, Decl(objectSpreadIndexSignature.ts, 25, 14)) +>T : Symbol(T, Decl(objectSpreadIndexSignature.ts, 25, 11)) + + let i: spread(T, { [n: number]: string }); +>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 26, 7)) +>T : Symbol(T, Decl(objectSpreadIndexSignature.ts, 25, 11)) +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 26, 24)) +} diff --git a/tests/baselines/reference/objectSpreadIndexSignature.types b/tests/baselines/reference/objectSpreadIndexSignature.types index 5eebc2ffa02b7..2900595e28d8f 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.types +++ b/tests/baselines/reference/objectSpreadIndexSignature.types @@ -1,4 +1,33 @@ === tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts === +class C { +>C : C + + a: number; +>a : number + + c: boolean; +>c : boolean +} +// index signatures are not allowed in object literals with spread types +let c: spread(C, { b: string, c?: string, [n: number]: string }); +>c : { b: string; c: string | boolean; a: number; } +>C : C +>b : string +>c : string +>n : number + +let n: number = c.a; +>n : number +>c.a : number +>c : { b: string; c: string | boolean; a: number; } +>a : number + +let s: string = c[12]; +>s : string +>c[12] : any +>c : { b: string; c: string | boolean; a: number; } +>12 : 12 + interface Indexed { >Indexed : Indexed @@ -25,12 +54,10 @@ let indexed2: Indexed2; >indexed2 : Indexed2 >Indexed2 : Indexed2 -let i = { ...indexed, b: 11 }; +let i: spread(Indexed, { b: number }); >i : { b: number; a: number; } ->{ ...indexed, b: 11 } : { b: number; a: number; } ->indexed : Indexed +>Indexed : Indexed >b : number ->11 : 11 // only indexed has indexer, so i[101]: any i[101]; @@ -38,15 +65,29 @@ i[101]; >i : { b: number; a: number; } >101 : 101 -let ii = { ...indexed, ...indexed2 }; ->ii : { [x: string]: number | boolean; c: boolean; a: number; } ->{ ...indexed, ...indexed2 } : { [x: string]: number | boolean; c: boolean; a: number; } ->indexed : Indexed ->indexed2 : Indexed2 +let ii: spread(spread(Indexed, Indexed2), { b: boolean, d: number }); +>ii : { b: boolean; d: number; c: boolean; a: number; } +>Indexed : Indexed +>Indexed2 : Indexed2 +>b : boolean +>d : number // both have indexer, so i[1001]: number | boolean -ii[1001]; ->ii[1001] : number | boolean ->ii : { [x: string]: number | boolean; c: boolean; a: number; } +let nb: number | boolean = ii[1001]; +>nb : number | boolean +>ii[1001] : any +>ii : { b: boolean; d: number; c: boolean; a: number; } >1001 : 1001 +function f(t: T) { +>f : (t: T) => void +>T : T +>t : T +>T : T + + let i: spread(T, { [n: number]: string }); +>i : spread(T, { [n: number]: string; }) +>T : T +>n : number +} + diff --git a/tests/baselines/reference/objectSpreadInference.js b/tests/baselines/reference/objectSpreadInference.js index 77930e565118e..31510fbecf5a2 100644 --- a/tests/baselines/reference/objectSpreadInference.js +++ b/tests/baselines/reference/objectSpreadInference.js @@ -4,8 +4,8 @@ interface Result { u: U; v: V; } -declare function infer(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V }; -declare function infer2(utv: { ...U, a: V, ...T }): { t: T, u: U, v: V }; +declare function infer(tuv: spread(spread(T, U), { a: V })): { t: T, u: U, v: V }; +declare function infer2(utv: spread(spread(U, { a: V }), T )): { t: T, u: U, v: V }; function generic(w: W, x: X, y: Y) { // should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter return infer({ ...w, ...x, a: y, b: "different type" }); diff --git a/tests/baselines/reference/objectSpreadInference.symbols b/tests/baselines/reference/objectSpreadInference.symbols index ddecc4d7e5d3f..4d3c17c908d61 100644 --- a/tests/baselines/reference/objectSpreadInference.symbols +++ b/tests/baselines/reference/objectSpreadInference.symbols @@ -17,7 +17,7 @@ interface Result { >v : Symbol(Result.v, Decl(objectSpreadInference.ts, 2, 9)) >V : Symbol(V, Decl(objectSpreadInference.ts, 0, 21)) } -declare function infer(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V }; +declare function infer(tuv: spread(spread(T, U), { a: V })): { t: T, u: U, v: V }; >infer : Symbol(infer, Decl(objectSpreadInference.ts, 4, 1)) >T : Symbol(T, Decl(objectSpreadInference.ts, 5, 23)) >U : Symbol(U, Decl(objectSpreadInference.ts, 5, 25)) @@ -25,34 +25,34 @@ declare function infer(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V }; >tuv : Symbol(tuv, Decl(objectSpreadInference.ts, 5, 30)) >T : Symbol(T, Decl(objectSpreadInference.ts, 5, 23)) >U : Symbol(U, Decl(objectSpreadInference.ts, 5, 25)) ->a : Symbol(a, Decl(objectSpreadInference.ts, 5, 48)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 5, 57)) >V : Symbol(V, Decl(objectSpreadInference.ts, 5, 27)) ->t : Symbol(t, Decl(objectSpreadInference.ts, 5, 59)) +>t : Symbol(t, Decl(objectSpreadInference.ts, 5, 69)) >T : Symbol(T, Decl(objectSpreadInference.ts, 5, 23)) ->u : Symbol(u, Decl(objectSpreadInference.ts, 5, 65)) +>u : Symbol(u, Decl(objectSpreadInference.ts, 5, 75)) >U : Symbol(U, Decl(objectSpreadInference.ts, 5, 25)) ->v : Symbol(v, Decl(objectSpreadInference.ts, 5, 71)) +>v : Symbol(v, Decl(objectSpreadInference.ts, 5, 81)) >V : Symbol(V, Decl(objectSpreadInference.ts, 5, 27)) -declare function infer2(utv: { ...U, a: V, ...T }): { t: T, u: U, v: V }; ->infer2 : Symbol(infer2, Decl(objectSpreadInference.ts, 5, 79)) +declare function infer2(utv: spread(spread(U, { a: V }), T )): { t: T, u: U, v: V }; +>infer2 : Symbol(infer2, Decl(objectSpreadInference.ts, 5, 89)) >T : Symbol(T, Decl(objectSpreadInference.ts, 6, 24)) >U : Symbol(U, Decl(objectSpreadInference.ts, 6, 26)) >V : Symbol(V, Decl(objectSpreadInference.ts, 6, 28)) >utv : Symbol(utv, Decl(objectSpreadInference.ts, 6, 31)) >U : Symbol(U, Decl(objectSpreadInference.ts, 6, 26)) ->a : Symbol(a, Decl(objectSpreadInference.ts, 6, 43)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 6, 54)) >V : Symbol(V, Decl(objectSpreadInference.ts, 6, 28)) >T : Symbol(T, Decl(objectSpreadInference.ts, 6, 24)) ->t : Symbol(t, Decl(objectSpreadInference.ts, 6, 60)) +>t : Symbol(t, Decl(objectSpreadInference.ts, 6, 71)) >T : Symbol(T, Decl(objectSpreadInference.ts, 6, 24)) ->u : Symbol(u, Decl(objectSpreadInference.ts, 6, 66)) +>u : Symbol(u, Decl(objectSpreadInference.ts, 6, 77)) >U : Symbol(U, Decl(objectSpreadInference.ts, 6, 26)) ->v : Symbol(v, Decl(objectSpreadInference.ts, 6, 72)) +>v : Symbol(v, Decl(objectSpreadInference.ts, 6, 83)) >V : Symbol(V, Decl(objectSpreadInference.ts, 6, 28)) function generic(w: W, x: X, y: Y) { ->generic : Symbol(generic, Decl(objectSpreadInference.ts, 6, 80)) +>generic : Symbol(generic, Decl(objectSpreadInference.ts, 6, 91)) >W : Symbol(W, Decl(objectSpreadInference.ts, 7, 17)) >X : Symbol(X, Decl(objectSpreadInference.ts, 7, 19)) >Y : Symbol(Y, Decl(objectSpreadInference.ts, 7, 22)) @@ -66,6 +66,8 @@ function generic(w: W, x: X, y: Y) { // should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter return infer({ ...w, ...x, a: y, b: "different type" }); >infer : Symbol(infer, Decl(objectSpreadInference.ts, 4, 1)) +>w : Symbol(w, Decl(objectSpreadInference.ts, 7, 26)) +>x : Symbol(x, Decl(objectSpreadInference.ts, 7, 31)) >a : Symbol(a, Decl(objectSpreadInference.ts, 9, 30)) >y : Symbol(y, Decl(objectSpreadInference.ts, 7, 37)) >b : Symbol(b, Decl(objectSpreadInference.ts, 9, 36)) @@ -82,18 +84,22 @@ let c: { c: number }; let i1 = infer({ ...b, ...c, a: 12 }); >i1 : Symbol(i1, Decl(objectSpreadInference.ts, 14, 3)) >infer : Symbol(infer, Decl(objectSpreadInference.ts, 4, 1)) +>b : Symbol(b, Decl(objectSpreadInference.ts, 11, 3)) +>c : Symbol(c, Decl(objectSpreadInference.ts, 12, 3)) >a : Symbol(a, Decl(objectSpreadInference.ts, 14, 28)) // can only infer { t: {}, u: {}, v: {} } let i2 = infer2({ ...b, ...c, a: 12 }); >i2 : Symbol(i2, Decl(objectSpreadInference.ts, 16, 3)) ->infer2 : Symbol(infer2, Decl(objectSpreadInference.ts, 5, 79)) +>infer2 : Symbol(infer2, Decl(objectSpreadInference.ts, 5, 89)) +>b : Symbol(b, Decl(objectSpreadInference.ts, 11, 3)) +>c : Symbol(c, Decl(objectSpreadInference.ts, 12, 3)) >a : Symbol(a, Decl(objectSpreadInference.ts, 16, 29)) // can only infer { t: {}, u: {}, v: {} } let i3 = generic(b, c, { a: 12 }); >i3 : Symbol(i3, Decl(objectSpreadInference.ts, 18, 3)) ->generic : Symbol(generic, Decl(objectSpreadInference.ts, 6, 80)) +>generic : Symbol(generic, Decl(objectSpreadInference.ts, 6, 91)) >b : Symbol(b, Decl(objectSpreadInference.ts, 11, 3)) >c : Symbol(c, Decl(objectSpreadInference.ts, 12, 3)) >a : Symbol(a, Decl(objectSpreadInference.ts, 18, 24)) diff --git a/tests/baselines/reference/objectSpreadInference.types b/tests/baselines/reference/objectSpreadInference.types index 3e71e29b83c48..f03a762dc5cdb 100644 --- a/tests/baselines/reference/objectSpreadInference.types +++ b/tests/baselines/reference/objectSpreadInference.types @@ -17,12 +17,12 @@ interface Result { >v : V >V : V } -declare function infer(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V }; ->infer : (tuv: { ...T; ...U; a: V; }) => { t: T; u: U; v: V; } +declare function infer(tuv: spread(spread(T, U), { a: V })): { t: T, u: U, v: V }; +>infer : (tuv: spread(spread(T, U), { a: V; })) => { t: T; u: U; v: V; } >T : T >U : U >V : V ->tuv : { ...T; ...U; a: V; } +>tuv : spread(spread(T, U), { a: V; }) >T : T >U : U >a : V @@ -34,12 +34,12 @@ declare function infer(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V }; >v : V >V : V -declare function infer2(utv: { ...U, a: V, ...T }): { t: T, u: U, v: V }; ->infer2 : (utv: { ...U; a: V; ...T }) => { t: T; u: U; v: V; } +declare function infer2(utv: spread(spread(U, { a: V }), T )): { t: T, u: U, v: V }; +>infer2 : (utv: spread(spread(U, { a: V; }), T)) => { t: T; u: U; v: V; } >T : T >U : U >V : V ->utv : { ...U; a: V; ...T } +>utv : spread(spread(U, { a: V; }), T) >U : U >a : V >V : V @@ -66,10 +66,10 @@ function generic(w: W, x: X, y: Y) { // should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter return infer({ ...w, ...x, a: y, b: "different type" }); >infer({ ...w, ...x, a: y, b: "different type" }) : { t: {}; u: {}; v: {}; } ->infer : (tuv: { ...T; ...U; a: V; }) => { t: T; u: U; v: V; } ->{ ...w, ...x, a: y, b: "different type" } : { ...W; ...X; a: Y; b: string; } ->w : any ->x : any +>infer : (tuv: spread(spread(T, U), { a: V; })) => { t: T; u: U; v: V; } +>{ ...w, ...x, a: y, b: "different type" } : spread(spread(W, X), { a: Y; b: string; }) +>w : W +>x : X >a : Y >y : Y >b : string @@ -87,10 +87,10 @@ let c: { c: number }; let i1 = infer({ ...b, ...c, a: 12 }); >i1 : { t: {}; u: {}; v: {}; } >infer({ ...b, ...c, a: 12 }) : { t: {}; u: {}; v: {}; } ->infer : (tuv: { ...T; ...U; a: V; }) => { t: T; u: U; v: V; } +>infer : (tuv: spread(spread(T, U), { a: V; })) => { t: T; u: U; v: V; } >{ ...b, ...c, a: 12 } : { a: number; c: number; b: number; } ->b : any ->c : any +>b : { b: number; } +>c : { c: number; } >a : number >12 : 12 @@ -98,10 +98,10 @@ let i1 = infer({ ...b, ...c, a: 12 }); let i2 = infer2({ ...b, ...c, a: 12 }); >i2 : { t: {}; u: {}; v: {}; } >infer2({ ...b, ...c, a: 12 }) : { t: {}; u: {}; v: {}; } ->infer2 : (utv: { ...U; a: V; ...T }) => { t: T; u: U; v: V; } +>infer2 : (utv: spread(spread(U, { a: V; }), T)) => { t: T; u: U; v: V; } >{ ...b, ...c, a: 12 } : { a: number; c: number; b: number; } ->b : any ->c : any +>b : { b: number; } +>c : { c: number; } >a : number >12 : 12 diff --git a/tests/baselines/reference/objectSpreadIntersection.js b/tests/baselines/reference/objectSpreadIntersection.js index 2ec6ad35413a3..eb2a51bae8811 100644 --- a/tests/baselines/reference/objectSpreadIntersection.js +++ b/tests/baselines/reference/objectSpreadIntersection.js @@ -3,7 +3,7 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { let tu: T | U; let uv: U & V; let result = { ...tu, ...uv, id: 'foo' }; - let assignable: { ...(T | U), ...(U & V), id: string } = result; + let assignable: spread(spread(T | U, U & V), { id: string }) = result; } // concrete types work interface A1 { a: number } @@ -15,26 +15,25 @@ let b12: B1 & B2; let result = { ...a12, ...b12 }; let sn: number & string = result.a; sn = result.b; -let assignable: { ...(A1 & A2), ...(B1 & B2) } = result; +let assignable: spread(A1 & A2, B1 & B2) = result; function tripleIntersection(t: T, u: U, v: V): void { let tuv: T & U & V; let result = { ...tuv, id: 'bar' }; - let assignable: { ...(T & U & V), id: string } = result; + let assignable: spread(T & U & V, { id: string }) = result; } function iteratedDoubleIntersection(t: T, u: U, v: V): void { let tu: T & U; let uv: U & V; let result = { ...tu, ...uv, id: 'baz' }; - let assignable: { ...(T & U), ...(U & V), id: string } = result; + let assignable: spread(spread(T & U, U & V), { id: string }) = result; } function iteratedIntersectionUnion(t: T, u: U, v: V): void { let tu: T & U; let uv: U | V; let result = { ...tu, ...uv, id: 'qux' }; - let assignable: { ...(T & U), ...(U | V), id: string } = result; + let assignable: spread(spread(T & U, U | V), { id: string }) = result; } - //// [objectSpreadIntersection.js] diff --git a/tests/baselines/reference/objectSpreadIntersection.symbols b/tests/baselines/reference/objectSpreadIntersection.symbols index bc63cb11348e4..12193da207a98 100644 --- a/tests/baselines/reference/objectSpreadIntersection.symbols +++ b/tests/baselines/reference/objectSpreadIntersection.symbols @@ -23,15 +23,17 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { let result = { ...tu, ...uv, id: 'foo' }; >result : Symbol(result, Decl(objectSpreadIntersection.ts, 3, 7)) +>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 1, 7)) +>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 2, 7)) >id : Symbol(id, Decl(objectSpreadIntersection.ts, 3, 32)) - let assignable: { ...(T | U), ...(U & V), id: string } = result; + let assignable: spread(spread(T | U, U & V), { id: string }) = result; >assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 4, 7)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 45)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 50)) >result : Symbol(result, Decl(objectSpreadIntersection.ts, 3, 7)) } // concrete types work @@ -63,6 +65,8 @@ let b12: B1 & B2; let result = { ...a12, ...b12 }; >result : Symbol(result, Decl(objectSpreadIntersection.ts, 13, 3)) +>a12 : Symbol(a12, Decl(objectSpreadIntersection.ts, 11, 3)) +>b12 : Symbol(b12, Decl(objectSpreadIntersection.ts, 12, 3)) let sn: number & string = result.a; >sn : Symbol(sn, Decl(objectSpreadIntersection.ts, 14, 3)) @@ -76,7 +80,7 @@ sn = result.b; >result : Symbol(result, Decl(objectSpreadIntersection.ts, 13, 3)) >b : Symbol(b, Decl(objectSpreadIntersection.ts, 9, 14), Decl(objectSpreadIntersection.ts, 10, 14)) -let assignable: { ...(A1 & A2), ...(B1 & B2) } = result; +let assignable: spread(A1 & A2, B1 & B2) = result; >assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 16, 3)) >A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 5, 1)) >A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 7, 26)) @@ -85,7 +89,7 @@ let assignable: { ...(A1 & A2), ...(B1 & B2) } = result; >result : Symbol(result, Decl(objectSpreadIntersection.ts, 13, 3)) function tripleIntersection(t: T, u: U, v: V): void { ->tripleIntersection : Symbol(tripleIntersection, Decl(objectSpreadIntersection.ts, 16, 56)) +>tripleIntersection : Symbol(tripleIntersection, Decl(objectSpreadIntersection.ts, 16, 50)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 18, 28)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 18, 30)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 18, 33)) @@ -104,14 +108,15 @@ function tripleIntersection(t: T, u: U, v: V): void { let result = { ...tuv, id: 'bar' }; >result : Symbol(result, Decl(objectSpreadIntersection.ts, 20, 7)) +>tuv : Symbol(tuv, Decl(objectSpreadIntersection.ts, 19, 7)) >id : Symbol(id, Decl(objectSpreadIntersection.ts, 20, 26)) - let assignable: { ...(T & U & V), id: string } = result; + let assignable: spread(T & U & V, { id: string }) = result; >assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 21, 7)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 18, 28)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 18, 30)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 18, 33)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 21, 37)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 21, 39)) >result : Symbol(result, Decl(objectSpreadIntersection.ts, 20, 7)) } function iteratedDoubleIntersection(t: T, u: U, v: V): void { @@ -138,15 +143,17 @@ function iteratedDoubleIntersection(t: T, u: U, v: V): void { let result = { ...tu, ...uv, id: 'baz' }; >result : Symbol(result, Decl(objectSpreadIntersection.ts, 26, 7)) +>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 24, 7)) +>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 25, 7)) >id : Symbol(id, Decl(objectSpreadIntersection.ts, 26, 32)) - let assignable: { ...(T & U), ...(U & V), id: string } = result; + let assignable: spread(spread(T & U, U & V), { id: string }) = result; >assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 27, 7)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 23, 36)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 23, 41)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 27, 45)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 27, 50)) >result : Symbol(result, Decl(objectSpreadIntersection.ts, 26, 7)) } function iteratedIntersectionUnion(t: T, u: U, v: V): void { @@ -173,16 +180,17 @@ function iteratedIntersectionUnion(t: T, u: U, v: V): void { let result = { ...tu, ...uv, id: 'qux' }; >result : Symbol(result, Decl(objectSpreadIntersection.ts, 32, 7)) +>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 30, 7)) +>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 31, 7)) >id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 32)) - let assignable: { ...(T & U), ...(U | V), id: string } = result; + let assignable: spread(spread(T & U, U | V), { id: string }) = result; >assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 33, 7)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 29, 35)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 29, 40)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 33, 45)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 33, 50)) >result : Symbol(result, Decl(objectSpreadIntersection.ts, 32, 7)) } - diff --git a/tests/baselines/reference/objectSpreadIntersection.types b/tests/baselines/reference/objectSpreadIntersection.types index e6a7b7c19ee7f..9ba434482ea0a 100644 --- a/tests/baselines/reference/objectSpreadIntersection.types +++ b/tests/baselines/reference/objectSpreadIntersection.types @@ -22,21 +22,21 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { >V : V let result = { ...tu, ...uv, id: 'foo' }; ->result : { ...T; ...U & V; id: string; } | { ...U; ...U & V; id: string; } ->{ ...tu, ...uv, id: 'foo' } : { ...T; ...U & V; id: string; } | { ...U; ...U & V; id: string; } ->tu : any ->uv : any +>result : spread(spread(T, U & V), { id: string; }) | spread(spread(U, U & V), { id: string; }) +>{ ...tu, ...uv, id: 'foo' } : spread(spread(T, U & V), { id: string; }) | spread(spread(U, U & V), { id: string; }) +>tu : T | U +>uv : U & V >id : string >'foo' : "foo" - let assignable: { ...(T | U), ...(U & V), id: string } = result; ->assignable : { ...T; ...U & V; id: string; } | { ...U; ...U & V; id: string; } + let assignable: spread(spread(T | U, U & V), { id: string }) = result; +>assignable : spread(spread(T, U & V), { id: string; }) | spread(spread(U, U & V), { id: string; }) >T : T >U : U >U : U >V : V >id : string ->result : { ...T; ...U & V; id: string; } | { ...U; ...U & V; id: string; } +>result : spread(spread(T, U & V), { id: string; }) | spread(spread(U, U & V), { id: string; }) } // concrete types work interface A1 { a: number } @@ -68,8 +68,8 @@ let b12: B1 & B2; let result = { ...a12, ...b12 }; >result : { b: number & string; a: number & string; } >{ ...a12, ...b12 } : { b: number & string; a: number & string; } ->a12 : any ->b12 : any +>a12 : A1 & A2 +>b12 : B1 & B2 let sn: number & string = result.a; >sn : number & string @@ -84,7 +84,7 @@ sn = result.b; >result : { b: number & string; a: number & string; } >b : number & string -let assignable: { ...(A1 & A2), ...(B1 & B2) } = result; +let assignable: spread(A1 & A2, B1 & B2) = result; >assignable : { b: number & string; a: number & string; } >A1 : A1 >A2 : A2 @@ -111,19 +111,19 @@ function tripleIntersection(t: T, u: U, v: V): void { >V : V let result = { ...tuv, id: 'bar' }; ->result : { ...T & U & V; id: string; } ->{ ...tuv, id: 'bar' } : { ...T & U & V; id: string; } ->tuv : any +>result : spread(T & U & V, { id: string; }) +>{ ...tuv, id: 'bar' } : spread(T & U & V, { id: string; }) +>tuv : T & U & V >id : string >'bar' : "bar" - let assignable: { ...(T & U & V), id: string } = result; ->assignable : { ...T & U & V; id: string; } + let assignable: spread(T & U & V, { id: string }) = result; +>assignable : spread(T & U & V, { id: string; }) >T : T >U : U >V : V >id : string ->result : { ...T & U & V; id: string; } +>result : spread(T & U & V, { id: string; }) } function iteratedDoubleIntersection(t: T, u: U, v: V): void { >iteratedDoubleIntersection : (t: T, u: U, v: V) => void @@ -148,21 +148,21 @@ function iteratedDoubleIntersection(t: T, u: U, v: V): void { >V : V let result = { ...tu, ...uv, id: 'baz' }; ->result : { ...T & U; ...U & V; id: string; } ->{ ...tu, ...uv, id: 'baz' } : { ...T & U; ...U & V; id: string; } ->tu : any ->uv : any +>result : spread(spread(T & U, U & V), { id: string; }) +>{ ...tu, ...uv, id: 'baz' } : spread(spread(T & U, U & V), { id: string; }) +>tu : T & U +>uv : U & V >id : string >'baz' : "baz" - let assignable: { ...(T & U), ...(U & V), id: string } = result; ->assignable : { ...T & U; ...U & V; id: string; } + let assignable: spread(spread(T & U, U & V), { id: string }) = result; +>assignable : spread(spread(T & U, U & V), { id: string; }) >T : T >U : U >U : U >V : V >id : string ->result : { ...T & U; ...U & V; id: string; } +>result : spread(spread(T & U, U & V), { id: string; }) } function iteratedIntersectionUnion(t: T, u: U, v: V): void { >iteratedIntersectionUnion : (t: T, u: U, v: V) => void @@ -187,21 +187,20 @@ function iteratedIntersectionUnion(t: T, u: U, v: V): void { >V : V let result = { ...tu, ...uv, id: 'qux' }; ->result : { ...T & U; ...U; id: string; } | { ...T & U; ...V; id: string; } ->{ ...tu, ...uv, id: 'qux' } : { ...T & U; ...U; id: string; } | { ...T & U; ...V; id: string; } ->tu : any ->uv : any +>result : spread(spread(T & U, U), { id: string; }) | spread(spread(T & U, V), { id: string; }) +>{ ...tu, ...uv, id: 'qux' } : spread(spread(T & U, U), { id: string; }) | spread(spread(T & U, V), { id: string; }) +>tu : T & U +>uv : U | V >id : string >'qux' : "qux" - let assignable: { ...(T & U), ...(U | V), id: string } = result; ->assignable : { ...T & U; ...U; id: string; } | { ...T & U; ...V; id: string; } + let assignable: spread(spread(T & U, U | V), { id: string }) = result; +>assignable : spread(spread(T & U, U), { id: string; }) | spread(spread(T & U, V), { id: string; }) >T : T >U : U >U : U >V : V >id : string ->result : { ...T & U; ...U; id: string; } | { ...T & U; ...V; id: string; } +>result : spread(spread(T & U, U), { id: string; }) | spread(spread(T & U, V), { id: string; }) } - diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index d9106d651a30d..8a2eb1f5c1f32 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -1,25 +1,29 @@ -tests/cases/conformance/types/spread/objectSpreadNegative.ts(13,21): error TS2339: Property 'x' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(16,5): error TS2322: Type '{ sn?: string | number; }' is not assignable to type '{ sn: string | number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(11,21): error TS2339: Property 'x' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(14,5): error TS2322: Type '{ sn?: string | number; }' is not assignable to type '{ sn: string | number; }'. Property 'sn' is optional in type '{ sn?: string | number; }' but required in type '{ sn: string | number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(23,1): error TS2322: Type '{ s: string; }' is not assignable to type '{ s: string; b: boolean; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(20,5): error TS2322: Type '{ s: string; }' is not assignable to type '{ s: string; b: boolean; }'. Property 'b' is missing in type '{ s: string; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322: Type '{ b: boolean; }' is not assignable to type '{ s: string; b: boolean; }'. - Property 's' is missing in type '{ b: boolean; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(35,20): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(42,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(46,12): error TS2339: Property 'b' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(52,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(57,11): error TS2339: Property 'a' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(22,1): error TS2322: Type 'Bool' is not assignable to type '{ s: string; b: boolean; }'. + Property 's' is missing in type 'Bool'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,36): error TS2300: Duplicate identifier 'b'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,53): error TS2300: Duplicate identifier 'b'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(30,12): error TS2339: Property 'null' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,17): error TS2339: Property 'undefined' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(35,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(38,20): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(40,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(45,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(50,11): error TS2339: Property 'a' does not exist on type 'spread(object)'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(54,12): error TS2339: Property 'b' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(60,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(63,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ x: number; }' has no compatible call signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,1): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(69,9): error TS2322: Type 'spread(T & V)' is not assignable to type 'spread(T & U)'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(71,5): error TS2322: Type 'spread(U)' is not assignable to type 'U'. -==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (16 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (20 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -29,9 +33,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS269 class PublicX { public x: number; } - let publicX: PublicX; - let privateOptionalX: PrivateOptionalX; - let o2 = { ...publicX, ...privateOptionalX }; + let o2: spread(PublicX, PrivateOptionalX); let sn: number = o2.x; // error, x is private ~ !!! error TS2339: Property 'x' does not exist on type '{}'. @@ -46,16 +48,15 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS269 // assignability as target interface Bool { b: boolean }; interface Str { s: string }; - let spread = { ...{ b: true }, ...{s: "foo" } }; - spread = { s: "foo" }; // error, missing 'b' - ~~~~~~ + let spread: spread(Bool, Str) = { s: "foo" }; // error, missing 'b' + ~~~~~~ !!! error TS2322: Type '{ s: string; }' is not assignable to type '{ s: string; b: boolean; }'. !!! error TS2322: Property 'b' is missing in type '{ s: string; }'. - let b = { b: false }; + let b: Bool; spread = b; // error, missing 's' ~~~~~~ -!!! error TS2322: Type '{ b: boolean; }' is not assignable to type '{ s: string; b: boolean; }'. -!!! error TS2322: Property 's' is missing in type '{ b: boolean; }'. +!!! error TS2322: Type 'Bool' is not assignable to type '{ s: string; b: boolean; }'. +!!! error TS2322: Property 's' is missing in type 'Bool'. // literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } @@ -65,6 +66,16 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS269 !!! error TS2300: Duplicate identifier 'b'. let duplicatedSpread = { ...o, ...o } + // null and undefined are just skipped + let spreadNull = { ...null }; + spreadNull.null; + ~~~~ +!!! error TS2339: Property 'null' does not exist on type '{}'. + let spreadUndefined = { ...undefined }; + spreadUndefined.undefined; + ~~~~~~~~~ +!!! error TS2339: Property 'undefined' does not exist on type '{}'. + // primitives are not allowed let spreadNum = { ...12 }; ~~~~~ @@ -88,6 +99,13 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS269 ~~~~~~~~~~~~ !!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. + // non primitive produces empty object + let obj: object = { a: 123 }; + let spreadObj = { ...obj }; + spreadObj.a; // error 'a' is not in {} + ~ +!!! error TS2339: Property 'a' does not exist on type 'spread(object)'. + // write-only properties get skipped let setterOnly = { ...{ set b (bad: number) { } } }; setterOnly.b = 12; // error, 'b' does not exist @@ -102,30 +120,23 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,14): error TS269 ~ !!! error TS2339: Property 'm' does not exist on type '{ p: number; }'. - // non primitive - let obj: object = { a: 123 }; - let spreadObj = { ...obj }; - spreadObj.a; // error 'a' is not in {} - ~ -!!! error TS2339: Property 'a' does not exist on type '{}'. + let callableConstructableSpread: spread(PublicX, { (n: number): number, new (p: number) }); + callableConstructableSpread(12); // error, no call signature + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ x: number; }' has no compatible call signatures. + new callableConstructableSpread(12); // error, no construct signature + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. - // generics - function f(t: T, u: U) { - return { ...t, ...u, id: 'id' }; - ~~~~ -!!! error TS2698: Spread types may only be created from object types. - } - function override(initial: U, override: U): U { + function override(initial: U, override: U, t: T, v: V): U { + // { ...T & V } is not assignable to { ...T & U } + let tvs: spread(T & V); + let mistake: spread(T & U) = tvs; + ~~~~~~~ +!!! error TS2322: Type 'spread(T & V)' is not assignable to type 'spread(T & U)'. + // { ...U } is not assignable to U return { ...initial, ...override }; - ~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type 'spread(U)' is not assignable to type 'U'. } - let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = - f({ a: 1, b: 'yes' }, { c: 'no', d: false }) - let overlap: { id: string, a: number, b: string } = - f({ a: 1 }, { a: 2, b: 'extra' }) - let overlapConflict: { id:string, a: string } = - f({ a: 1 }, { a: 'mismatch' }) - let overwriteId: { id: string, a: number, c: number, d: string } = - f({ a: 1, id: true }, { c: 1, d: 'no' }) \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index fd834b6ef9ce1..22662530ab32a 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -8,9 +8,7 @@ class PrivateOptionalX { class PublicX { public x: number; } -let publicX: PublicX; -let privateOptionalX: PrivateOptionalX; -let o2 = { ...publicX, ...privateOptionalX }; +let o2: spread(PublicX, PrivateOptionalX); let sn: number = o2.x; // error, x is private let optionalString: { sn?: string }; let optionalNumber: { sn?: number }; @@ -20,15 +18,20 @@ let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumbe // assignability as target interface Bool { b: boolean }; interface Str { s: string }; -let spread = { ...{ b: true }, ...{s: "foo" } }; -spread = { s: "foo" }; // error, missing 'b' -let b = { b: false }; +let spread: spread(Bool, Str) = { s: "foo" }; // error, missing 'b' +let b: Bool; spread = b; // error, missing 's' // literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } +// null and undefined are just skipped +let spreadNull = { ...null }; +spreadNull.null; +let spreadUndefined = { ...undefined }; +spreadUndefined.undefined; + // primitives are not allowed let spreadNum = { ...12 }; let spreadSum = { ...1 + 1 }; @@ -42,6 +45,11 @@ spreadStr.charAt(1); // error, no methods either let spreadFunc = { ...function () { } } spreadFunc(); // error, no call signature +// non primitive produces empty object +let obj: object = { a: 123 }; +let spreadObj = { ...obj }; +spreadObj.a; // error 'a' is not in {} + // write-only properties get skipped let setterOnly = { ...{ set b (bad: number) { } } }; setterOnly.b = 12; // error, 'b' does not exist @@ -52,26 +60,17 @@ let c: C = new C() let spreadC = { ...c } spreadC.m(); // error 'm' is not in '{ ... c }' -// non primitive -let obj: object = { a: 123 }; -let spreadObj = { ...obj }; -spreadObj.a; // error 'a' is not in {} +let callableConstructableSpread: spread(PublicX, { (n: number): number, new (p: number) }); +callableConstructableSpread(12); // error, no call signature +new callableConstructableSpread(12); // error, no construct signature -// generics -function f(t: T, u: U) { - return { ...t, ...u, id: 'id' }; -} -function override(initial: U, override: U): U { +function override(initial: U, override: U, t: T, v: V): U { + // { ...T & V } is not assignable to { ...T & U } + let tvs: spread(T & V); + let mistake: spread(T & U) = tvs; + // { ...U } is not assignable to U return { ...initial, ...override }; } -let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = - f({ a: 1, b: 'yes' }, { c: 'no', d: false }) -let overlap: { id: string, a: number, b: string } = - f({ a: 1 }, { a: 2, b: 'extra' }) -let overlapConflict: { id:string, a: string } = - f({ a: 1 }, { a: 'mismatch' }) -let overwriteId: { id: string, a: number, c: number, d: string } = - f({ a: 1, id: true }, { c: 1, d: 'no' }) //// [objectSpreadNegative.js] @@ -95,22 +94,24 @@ var PublicX = (function () { } return PublicX; }()); -var publicX; -var privateOptionalX; -var o2 = __assign({}, publicX, privateOptionalX); +var o2; var sn = o2.x; // error, x is private var optionalString; var optionalNumber; var allOptional = __assign({}, optionalString, optionalNumber); ; ; -var spread = __assign({ b: true }, { s: "foo" }); -spread = { s: "foo" }; // error, missing 'b' -var b = { b: false }; +var spread = { s: "foo" }; // error, missing 'b' +var b; spread = b; // error, missing 's' // literal repeats are not allowed, but spread repeats are fine var duplicated = __assign({ b: 'bad' }, o, { b: 'bad' }, o2, { b: 'bad' }); var duplicatedSpread = __assign({}, o, o); +// null and undefined are just skipped +var spreadNull = __assign({}, null); +spreadNull.null; +var spreadUndefined = __assign({}, undefined); +spreadUndefined.undefined; // primitives are not allowed var spreadNum = __assign({}, 12); var spreadSum = __assign({}, 1 + 1); @@ -123,6 +124,10 @@ spreadStr.charAt(1); // error, no methods either // functions are skipped var spreadFunc = __assign({}, function () { }); spreadFunc(); // error, no call signature +// non primitive produces empty object +var obj = { a: 123 }; +var spreadObj = __assign({}, obj); +spreadObj.a; // error 'a' is not in {} // write-only properties get skipped var setterOnly = __assign({ set b(bad) { } }); setterOnly.b = 12; // error, 'b' does not exist @@ -137,18 +142,13 @@ var C = (function () { var c = new C(); var spreadC = __assign({}, c); spreadC.m(); // error 'm' is not in '{ ... c }' -// non primitive -var obj = { a: 123 }; -var spreadObj = __assign({}, obj); -spreadObj.a; // error 'a' is not in {} -// generics -function f(t, u) { - return __assign({}, t, u, { id: 'id' }); -} -function override(initial, override) { +var callableConstructableSpread; +callableConstructableSpread(12); // error, no call signature +new callableConstructableSpread(12); // error, no construct signature +function override(initial, override, t, v) { + // { ...T & V } is not assignable to { ...T & U } + var tvs; + var mistake = tvs; + // { ...U } is not assignable to U return __assign({}, initial, override); } -var exclusive = f({ a: 1, b: 'yes' }, { c: 'no', d: false }); -var overlap = f({ a: 1 }, { a: 2, b: 'extra' }); -var overlapConflict = f({ a: 1 }, { a: 'mismatch' }); -var overwriteId = f({ a: 1, id: true }, { c: 1, d: 'no' }); diff --git a/tests/baselines/reference/objectSpreadScenarios.js b/tests/baselines/reference/objectSpreadScenarios.js index 96ac98d2d3593..901499447ad04 100644 --- a/tests/baselines/reference/objectSpreadScenarios.js +++ b/tests/baselines/reference/objectSpreadScenarios.js @@ -1,13 +1,13 @@ //// [objectSpreadScenarios.ts] interface A1 { a: boolean } interface B1 { b: number }; -function override(initial: U, override: U): { ...U, ...U } { +function override(initial: U, override: U): spread(U, U) { return { ...initial, ...override }; } -function update(this: { u: { ...U } }, override: U): void { +function update(this: { u: spread(U) }, override: U): void { this.u = { ...this.u, ...override }; } -function mixin(one: T, two: U): { ...T, ...U } { +function mixin(one: T, two: U): spread(T, U) { return { ...one, ...two }; } let a1: A1 = { a: true }; diff --git a/tests/baselines/reference/objectSpreadScenarios.symbols b/tests/baselines/reference/objectSpreadScenarios.symbols index cf1e1833ac968..29b18808a8e4b 100644 --- a/tests/baselines/reference/objectSpreadScenarios.symbols +++ b/tests/baselines/reference/objectSpreadScenarios.symbols @@ -7,7 +7,7 @@ interface B1 { b: number }; >B1 : Symbol(B1, Decl(objectSpreadScenarios.ts, 0, 27)) >b : Symbol(B1.b, Decl(objectSpreadScenarios.ts, 1, 14)) -function override(initial: U, override: U): { ...U, ...U } { +function override(initial: U, override: U): spread(U, U) { >override : Symbol(override, Decl(objectSpreadScenarios.ts, 1, 27)) >U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18)) >initial : Symbol(initial, Decl(objectSpreadScenarios.ts, 2, 21)) @@ -18,14 +18,16 @@ function override(initial: U, override: U): { ...U, ...U } { >U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18)) return { ...initial, ...override }; +>initial : Symbol(initial, Decl(objectSpreadScenarios.ts, 2, 21)) +>override : Symbol(override, Decl(objectSpreadScenarios.ts, 2, 32)) } -function update(this: { u: { ...U } }, override: U): void { +function update(this: { u: spread(U) }, override: U): void { >update : Symbol(update, Decl(objectSpreadScenarios.ts, 4, 1)) >U : Symbol(U, Decl(objectSpreadScenarios.ts, 5, 16)) >this : Symbol(this, Decl(objectSpreadScenarios.ts, 5, 19)) >u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26)) >U : Symbol(U, Decl(objectSpreadScenarios.ts, 5, 16)) ->override : Symbol(override, Decl(objectSpreadScenarios.ts, 5, 41)) +>override : Symbol(override, Decl(objectSpreadScenarios.ts, 5, 42)) >U : Symbol(U, Decl(objectSpreadScenarios.ts, 5, 16)) this.u = { ...this.u, ...override }; @@ -35,8 +37,9 @@ function update(this: { u: { ...U } }, override: U): void { >this.u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26)) >this : Symbol(this, Decl(objectSpreadScenarios.ts, 5, 19)) >u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26)) +>override : Symbol(override, Decl(objectSpreadScenarios.ts, 5, 42)) } -function mixin(one: T, two: U): { ...T, ...U } { +function mixin(one: T, two: U): spread(T, U) { >mixin : Symbol(mixin, Decl(objectSpreadScenarios.ts, 7, 1)) >T : Symbol(T, Decl(objectSpreadScenarios.ts, 8, 15)) >U : Symbol(U, Decl(objectSpreadScenarios.ts, 8, 17)) @@ -48,6 +51,8 @@ function mixin(one: T, two: U): { ...T, ...U } { >U : Symbol(U, Decl(objectSpreadScenarios.ts, 8, 17)) return { ...one, ...two }; +>one : Symbol(one, Decl(objectSpreadScenarios.ts, 8, 21)) +>two : Symbol(two, Decl(objectSpreadScenarios.ts, 8, 28)) } let a1: A1 = { a: true }; >a1 : Symbol(a1, Decl(objectSpreadScenarios.ts, 11, 3)) diff --git a/tests/baselines/reference/objectSpreadScenarios.types b/tests/baselines/reference/objectSpreadScenarios.types index 2d1aa47bd50a8..232a8b96ab063 100644 --- a/tests/baselines/reference/objectSpreadScenarios.types +++ b/tests/baselines/reference/objectSpreadScenarios.types @@ -7,8 +7,8 @@ interface B1 { b: number }; >B1 : B1 >b : number -function override(initial: U, override: U): { ...U, ...U } { ->override : (initial: U, override: U) => { ...U } +function override(initial: U, override: U): spread(U, U) { +>override : (initial: U, override: U) => spread(U) >U : U >initial : U >U : U @@ -18,32 +18,32 @@ function override(initial: U, override: U): { ...U, ...U } { >U : U return { ...initial, ...override }; ->{ ...initial, ...override } : { ...U } ->initial : any ->override : any +>{ ...initial, ...override } : spread(U) +>initial : U +>override : U } -function update(this: { u: { ...U } }, override: U): void { ->update : (this: { u: { ...U }; }, override: U) => void +function update(this: { u: spread(U) }, override: U): void { +>update : (this: { u: spread(U); }, override: U) => void >U : U ->this : { u: { ...U }; } ->u : { ...U } +>this : { u: spread(U); } +>u : spread(U) >U : U >override : U >U : U this.u = { ...this.u, ...override }; ->this.u = { ...this.u, ...override } : { ...U } ->this.u : { ...U } ->this : { u: { ...U }; } ->u : { ...U } ->{ ...this.u, ...override } : { ...U } ->this.u : { ...U } ->this : { u: { ...U }; } ->u : { ...U } ->override : any +>this.u = { ...this.u, ...override } : spread(U) +>this.u : spread(U) +>this : { u: spread(U); } +>u : spread(U) +>{ ...this.u, ...override } : spread(U) +>this.u : spread(U) +>this : { u: spread(U); } +>u : spread(U) +>override : U } -function mixin(one: T, two: U): { ...T, ...U } { ->mixin : (one: T, two: U) => { ...T; ...U } +function mixin(one: T, two: U): spread(T, U) { +>mixin : (one: T, two: U) => spread(T, U) >T : T >U : U >one : T @@ -54,9 +54,9 @@ function mixin(one: T, two: U): { ...T, ...U } { >U : U return { ...one, ...two }; ->{ ...one, ...two } : { ...T; ...U } ->one : any ->two : any +>{ ...one, ...two } : spread(T, U) +>one : T +>two : U } let a1: A1 = { a: true }; >a1 : A1 @@ -76,24 +76,24 @@ a1 = override(a1, { a: false }); >a1 = override(a1, { a: false }) : { a: boolean; } >a1 : A1 >override(a1, { a: false }) : { a: boolean; } ->override : (initial: U, override: U) => { ...U } +>override : (initial: U, override: U) => spread(U) >a1 : A1 >{ a: false } : { a: false; } >a : boolean >false : false let host = { u: a1, update }; ->host : { u: A1; update: (this: { u: { ...U }; }, override: U) => void; } ->{ u: a1, update } : { u: A1; update: (this: { u: { ...U }; }, override: U) => void; } +>host : { u: A1; update: (this: { u: spread(U); }, override: U) => void; } +>{ u: a1, update } : { u: A1; update: (this: { u: spread(U); }, override: U) => void; } >u : A1 >a1 : A1 ->update : (this: { u: { ...U }; }, override: U) => void +>update : (this: { u: spread(U); }, override: U) => void host.update({ a: false }); >host.update({ a: false }) : void ->host.update : (this: { u: { ...U }; }, override: U) => void ->host : { u: A1; update: (this: { u: { ...U }; }, override: U) => void; } ->update : (this: { u: { ...U }; }, override: U) => void +>host.update : (this: { u: spread(U); }, override: U) => void +>host : { u: A1; update: (this: { u: spread(U); }, override: U) => void; } +>update : (this: { u: spread(U); }, override: U) => void >{ a: false } : { a: false; } >a : boolean >false : false @@ -101,7 +101,7 @@ host.update({ a: false }); let mixed = mixin(a1, b1); >mixed : { b: number; a: boolean; } >mixin(a1, b1) : { b: number; a: boolean; } ->mixin : (one: T, two: U) => { ...T; ...U } +>mixin : (one: T, two: U) => spread(T, U) >a1 : A1 >b1 : B1 diff --git a/tests/baselines/reference/objectSpreadUnion.js b/tests/baselines/reference/objectSpreadUnion.js index b3a114c772218..4dcfe8162ca58 100644 --- a/tests/baselines/reference/objectSpreadUnion.js +++ b/tests/baselines/reference/objectSpreadUnion.js @@ -5,23 +5,21 @@ interface A2 { a: string } let a12: A1 | A2; let result = { ...a12 }; let sn: number | string = result.a; -let assignable: { ...(A1 | A2) } = result; +let assignable: spread(A1 | A2) = result; function tripleUnion(t: T, u: U, v: V): void { let tuv: T | U | V; let result = { ...tuv, id: 'foo' }; - let expected: { ...T, id: string } | { ...U, id: string } | { ...V, id: string } = result; - let assignable: { ...(T | U | V), id: string } = result; + let expected: spread(T, { id: string }) | spread(U, { id: string }) | spread(V, { id: string }) = result; + let assignable: spread(T | U | V, { id: string }) = result; } function iteratedDoubleUnion(t: T, u: U, v: V): void { let tu: T | U; let uv: U | V; let result = { ...tu, ...uv, id: 'bar' }; - let expected: { ...T, ...U, id: string } | { ...T, ...V, id: string } | { ...U, id: string } | { ...U, ...V, id: string }; - let assignable: { ...(T | U), ...(U | V), id: string } = result; + let expected: spread(spread(T, U), { id: string }) | spread(spread(T, V), { id: string }) | spread(U, { id: string }) | spread(spread(U, V), { id: string }); + let assignable: spread(spread(T | U, U | V), { id: string }) = result; } - - //// [objectSpreadUnion.js] diff --git a/tests/baselines/reference/objectSpreadUnion.symbols b/tests/baselines/reference/objectSpreadUnion.symbols index d630fde518b52..532e4b8ecb103 100644 --- a/tests/baselines/reference/objectSpreadUnion.symbols +++ b/tests/baselines/reference/objectSpreadUnion.symbols @@ -15,6 +15,7 @@ let a12: A1 | A2; let result = { ...a12 }; >result : Symbol(result, Decl(objectSpreadUnion.ts, 4, 3)) +>a12 : Symbol(a12, Decl(objectSpreadUnion.ts, 3, 3)) let sn: number | string = result.a; >sn : Symbol(sn, Decl(objectSpreadUnion.ts, 5, 3)) @@ -22,14 +23,14 @@ let sn: number | string = result.a; >result : Symbol(result, Decl(objectSpreadUnion.ts, 4, 3)) >a : Symbol(a, Decl(objectSpreadUnion.ts, 1, 14), Decl(objectSpreadUnion.ts, 2, 14)) -let assignable: { ...(A1 | A2) } = result; +let assignable: spread(A1 | A2) = result; >assignable : Symbol(assignable, Decl(objectSpreadUnion.ts, 6, 3)) >A1 : Symbol(A1, Decl(objectSpreadUnion.ts, 0, 0)) >A2 : Symbol(A2, Decl(objectSpreadUnion.ts, 1, 26)) >result : Symbol(result, Decl(objectSpreadUnion.ts, 4, 3)) function tripleUnion(t: T, u: U, v: V): void { ->tripleUnion : Symbol(tripleUnion, Decl(objectSpreadUnion.ts, 6, 42)) +>tripleUnion : Symbol(tripleUnion, Decl(objectSpreadUnion.ts, 6, 41)) >T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26)) @@ -48,24 +49,25 @@ function tripleUnion(t: T, u: U, v: V): void { let result = { ...tuv, id: 'foo' }; >result : Symbol(result, Decl(objectSpreadUnion.ts, 10, 7)) +>tuv : Symbol(tuv, Decl(objectSpreadUnion.ts, 9, 7)) >id : Symbol(id, Decl(objectSpreadUnion.ts, 10, 26)) - let expected: { ...T, id: string } | { ...U, id: string } | { ...V, id: string } = result; + let expected: spread(T, { id: string }) | spread(U, { id: string }) | spread(V, { id: string }) = result; >expected : Symbol(expected, Decl(objectSpreadUnion.ts, 11, 7)) >T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 25)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 29)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 48)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 57)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 71)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 85)) >result : Symbol(result, Decl(objectSpreadUnion.ts, 10, 7)) - let assignable: { ...(T | U | V), id: string } = result; + let assignable: spread(T | U | V, { id: string }) = result; >assignable : Symbol(assignable, Decl(objectSpreadUnion.ts, 12, 7)) >T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 12, 37)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 12, 39)) >result : Symbol(result, Decl(objectSpreadUnion.ts, 10, 7)) } function iteratedDoubleUnion(t: T, u: U, v: V): void { @@ -92,31 +94,31 @@ function iteratedDoubleUnion(t: T, u: U, v: V): void { let result = { ...tu, ...uv, id: 'bar' }; >result : Symbol(result, Decl(objectSpreadUnion.ts, 17, 7)) +>tu : Symbol(tu, Decl(objectSpreadUnion.ts, 15, 7)) +>uv : Symbol(uv, Decl(objectSpreadUnion.ts, 16, 7)) >id : Symbol(id, Decl(objectSpreadUnion.ts, 17, 32)) - let expected: { ...T, ...U, id: string } | { ...T, ...V, id: string } | { ...U, id: string } | { ...U, ...V, id: string }; + let expected: spread(spread(T, U), { id: string }) | spread(spread(T, V), { id: string }) | spread(U, { id: string }) | spread(spread(U, V), { id: string }); >expected : Symbol(expected, Decl(objectSpreadUnion.ts, 18, 7)) >T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 31)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 40)) >T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 60)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 79)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 83)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 107)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 112)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 146)) - let assignable: { ...(T | U), ...(U | V), id: string } = result; + let assignable: spread(spread(T | U, U | V), { id: string }) = result; >assignable : Symbol(assignable, Decl(objectSpreadUnion.ts, 19, 7)) >T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 19, 45)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 19, 50)) >result : Symbol(result, Decl(objectSpreadUnion.ts, 17, 7)) } - - diff --git a/tests/baselines/reference/objectSpreadUnion.types b/tests/baselines/reference/objectSpreadUnion.types index 20633295acba3..33d642a2f2f72 100644 --- a/tests/baselines/reference/objectSpreadUnion.types +++ b/tests/baselines/reference/objectSpreadUnion.types @@ -16,7 +16,7 @@ let a12: A1 | A2; let result = { ...a12 }; >result : { a: number; } | { a: string; } >{ ...a12 } : { a: number; } | { a: string; } ->a12 : any +>a12 : A1 | A2 let sn: number | string = result.a; >sn : string | number @@ -24,7 +24,7 @@ let sn: number | string = result.a; >result : { a: number; } | { a: string; } >a : string | number -let assignable: { ...(A1 | A2) } = result; +let assignable: spread(A1 | A2) = result; >assignable : { a: number; } | { a: string; } >A1 : A1 >A2 : A2 @@ -49,29 +49,29 @@ function tripleUnion(t: T, u: U, v: V): void { >V : V let result = { ...tuv, id: 'foo' }; ->result : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; } ->{ ...tuv, id: 'foo' } : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; } ->tuv : any +>result : spread(T, { id: string; }) | spread(U, { id: string; }) | spread(V, { id: string; }) +>{ ...tuv, id: 'foo' } : spread(T, { id: string; }) | spread(U, { id: string; }) | spread(V, { id: string; }) +>tuv : T | U | V >id : string >'foo' : "foo" - let expected: { ...T, id: string } | { ...U, id: string } | { ...V, id: string } = result; ->expected : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; } + let expected: spread(T, { id: string }) | spread(U, { id: string }) | spread(V, { id: string }) = result; +>expected : spread(T, { id: string; }) | spread(U, { id: string; }) | spread(V, { id: string; }) >T : T >id : string >U : U >id : string >V : V >id : string ->result : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; } +>result : spread(T, { id: string; }) | spread(U, { id: string; }) | spread(V, { id: string; }) - let assignable: { ...(T | U | V), id: string } = result; ->assignable : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; } + let assignable: spread(T | U | V, { id: string }) = result; +>assignable : spread(T, { id: string; }) | spread(U, { id: string; }) | spread(V, { id: string; }) >T : T >U : U >V : V >id : string ->result : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; } +>result : spread(T, { id: string; }) | spread(U, { id: string; }) | spread(V, { id: string; }) } function iteratedDoubleUnion(t: T, u: U, v: V): void { >iteratedDoubleUnion : (t: T, u: U, v: V) => void @@ -96,15 +96,15 @@ function iteratedDoubleUnion(t: T, u: U, v: V): void { >V : V let result = { ...tu, ...uv, id: 'bar' }; ->result : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...V; id: string; } ->{ ...tu, ...uv, id: 'bar' } : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...V; id: string; } ->tu : any ->uv : any +>result : spread(U, { id: string; }) | spread(spread(T, U), { id: string; }) | spread(spread(T, V), { id: string; }) | spread(spread(U, V), { id: string; }) +>{ ...tu, ...uv, id: 'bar' } : spread(U, { id: string; }) | spread(spread(T, U), { id: string; }) | spread(spread(T, V), { id: string; }) | spread(spread(U, V), { id: string; }) +>tu : T | U +>uv : U | V >id : string >'bar' : "bar" - let expected: { ...T, ...U, id: string } | { ...T, ...V, id: string } | { ...U, id: string } | { ...U, ...V, id: string }; ->expected : { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; id: string; } | { ...U; ...V; id: string; } + let expected: spread(spread(T, U), { id: string }) | spread(spread(T, V), { id: string }) | spread(U, { id: string }) | spread(spread(U, V), { id: string }); +>expected : spread(spread(T, U), { id: string; }) | spread(spread(T, V), { id: string; }) | spread(U, { id: string; }) | spread(spread(U, V), { id: string; }) >T : T >U : U >id : string @@ -117,15 +117,13 @@ function iteratedDoubleUnion(t: T, u: U, v: V): void { >V : V >id : string - let assignable: { ...(T | U), ...(U | V), id: string } = result; ->assignable : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...V; id: string; } + let assignable: spread(spread(T | U, U | V), { id: string }) = result; +>assignable : spread(U, { id: string; }) | spread(spread(T, U), { id: string; }) | spread(spread(T, V), { id: string; }) | spread(spread(U, V), { id: string; }) >T : T >U : U >U : U >V : V >id : string ->result : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...V; id: string; } +>result : spread(U, { id: string; }) | spread(spread(T, U), { id: string; }) | spread(spread(T, V), { id: string; }) | spread(spread(U, V), { id: string; }) } - - diff --git a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt index 5088390f9eea9..116f5e9095abc 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt +++ b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt @@ -1,12 +1,4 @@ -tests/cases/compiler/spreadInvalidArgumentType.ts(31,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(33,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(35,16): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(36,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(38,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(41,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(42,16): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(44,17): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(45,17): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(47,17): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(48,17): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(55,17): error TS2698: Spread types may only be created from object types. @@ -14,7 +6,7 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(56,17): error TS2698: Spread t tests/cases/compiler/spreadInvalidArgumentType.ts(58,17): error TS2698: Spread types may only be created from object types. -==== tests/cases/compiler/spreadInvalidArgumentType.ts (14 errors) ==== +==== tests/cases/compiler/spreadInvalidArgumentType.ts (6 errors) ==== enum E { v1, v2 }; function f(p1: T, p2: T[]) { @@ -45,39 +37,23 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(58,17): error TS2698: Spread t var e: E; - var o1 = { ...p1 }; // Error, generic type paramterre - ~~~~~ -!!! error TS2698: Spread types may only be created from object types. + var o1 = { ...p1 }; // OK, generic type parameter var o2 = { ...p2 }; // OK - var o3 = { ...t }; // Error, generic type paramter - ~~~~ -!!! error TS2698: Spread types may only be created from object types. + var o3 = { ...t }; // OK, generic type parameter - var o4 = { ...i }; // Error, index access - ~~~~ -!!! error TS2698: Spread types may only be created from object types. + var o4 = { ...i }; // OK, index access var o5 = { ...k }; // Error, index ~~~~ !!! error TS2698: Spread types may only be created from object types. - var o6 = { ...mapped_generic }; // Error, generic mapped object type - ~~~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. + var o6 = { ...mapped_generic }; // OK, generic mapped object type var o7 = { ...mapped }; // OK, non-generic mapped type - var o8 = { ...union_generic }; // Error, union with generic type parameter - ~~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. - var o9 = { ...union_primitive }; // Error, union with generic type parameter - ~~~~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. + var o8 = { ...union_generic }; // OK, union with generic type parameter + var o9 = { ...union_primitive }; // OK, union with generic type parameter - var o10 = { ...intersection_generic }; // Error, intersection with generic type parameter - ~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. - var o11 = { ...intersection_premitive }; // Error, intersection with generic type parameter - ~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. + var o10 = { ...intersection_generic }; // OK, intersection with generic type parameter + var o11 = { ...intersection_premitive }; // OK, intersection with generic type parameter var o12 = { ...num }; // Error ~~~~~~ @@ -101,4 +77,5 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(58,17): error TS2698: Spread t var o19 = { ...e }; // Error, enum ~~~~ !!! error TS2698: Spread types may only be created from object types. - } \ No newline at end of file + } + \ No newline at end of file diff --git a/tests/baselines/reference/spreadInvalidArgumentType.js b/tests/baselines/reference/spreadInvalidArgumentType.js index 26f958f224da3..3490d1300a63f 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.js +++ b/tests/baselines/reference/spreadInvalidArgumentType.js @@ -29,21 +29,21 @@ function f(p1: T, p2: T[]) { var e: E; - var o1 = { ...p1 }; // Error, generic type paramterre + var o1 = { ...p1 }; // OK, generic type parameter var o2 = { ...p2 }; // OK - var o3 = { ...t }; // Error, generic type paramter + var o3 = { ...t }; // OK, generic type parameter - var o4 = { ...i }; // Error, index access + var o4 = { ...i }; // OK, index access var o5 = { ...k }; // Error, index - var o6 = { ...mapped_generic }; // Error, generic mapped object type + var o6 = { ...mapped_generic }; // OK, generic mapped object type var o7 = { ...mapped }; // OK, non-generic mapped type - var o8 = { ...union_generic }; // Error, union with generic type parameter - var o9 = { ...union_primitive }; // Error, union with generic type parameter + var o8 = { ...union_generic }; // OK, union with generic type parameter + var o9 = { ...union_primitive }; // OK, union with generic type parameter - var o10 = { ...intersection_generic }; // Error, intersection with generic type parameter - var o11 = { ...intersection_premitive }; // Error, intersection with generic type parameter + var o10 = { ...intersection_generic }; // OK, intersection with generic type parameter + var o11 = { ...intersection_premitive }; // OK, intersection with generic type parameter var o12 = { ...num }; // Error var o13 = { ...str }; // Error @@ -57,7 +57,8 @@ function f(p1: T, p2: T[]) { var o18 = { ...literal_number }; // Error var o19 = { ...e }; // Error, enum -} +} + //// [spreadInvalidArgumentType.js] var __assign = (this && this.__assign) || Object.assign || function(t) { @@ -92,17 +93,17 @@ function f(p1, p2) { var literal_string; var literal_number; var e; - var o1 = __assign({}, p1); // Error, generic type paramterre + var o1 = __assign({}, p1); // OK, generic type parameter var o2 = __assign({}, p2); // OK - var o3 = __assign({}, t); // Error, generic type paramter - var o4 = __assign({}, i); // Error, index access + var o3 = __assign({}, t); // OK, generic type parameter + var o4 = __assign({}, i); // OK, index access var o5 = __assign({}, k); // Error, index - var o6 = __assign({}, mapped_generic); // Error, generic mapped object type + var o6 = __assign({}, mapped_generic); // OK, generic mapped object type var o7 = __assign({}, mapped); // OK, non-generic mapped type - var o8 = __assign({}, union_generic); // Error, union with generic type parameter - var o9 = __assign({}, union_primitive); // Error, union with generic type parameter - var o10 = __assign({}, intersection_generic); // Error, intersection with generic type parameter - var o11 = __assign({}, intersection_premitive); // Error, intersection with generic type parameter + var o8 = __assign({}, union_generic); // OK, union with generic type parameter + var o9 = __assign({}, union_primitive); // OK, union with generic type parameter + var o10 = __assign({}, intersection_generic); // OK, intersection with generic type parameter + var o11 = __assign({}, intersection_premitive); // OK, intersection with generic type parameter var o12 = __assign({}, num); // Error var o13 = __assign({}, str); // Error var o14 = __assign({}, u); // OK diff --git a/tests/baselines/reference/spreadLeftDeep.js b/tests/baselines/reference/spreadLeftDeep.js new file mode 100644 index 0000000000000..c146ffac5a214 --- /dev/null +++ b/tests/baselines/reference/spreadLeftDeep.js @@ -0,0 +1,16 @@ +//// [spreadLeftDeep.ts] +function f(t: T, u: U, v: V, w: W) { + // right-deep structure (T (U (V W)) should get transformed to + // left-deep structure (((T U) V) W) + let x: spread(T, spread(U, spread(V, W))); + return x; +} + + +//// [spreadLeftDeep.js] +function f(t, u, v, w) { + // right-deep structure (T (U (V W)) should get transformed to + // left-deep structure (((T U) V) W) + var x; + return x; +} diff --git a/tests/baselines/reference/spreadLeftDeep.symbols b/tests/baselines/reference/spreadLeftDeep.symbols new file mode 100644 index 0000000000000..be7b16a1bf876 --- /dev/null +++ b/tests/baselines/reference/spreadLeftDeep.symbols @@ -0,0 +1,29 @@ +=== tests/cases/conformance/types/spread/spreadLeftDeep.ts === +function f(t: T, u: U, v: V, w: W) { +>f : Symbol(f, Decl(spreadLeftDeep.ts, 0, 0)) +>T : Symbol(T, Decl(spreadLeftDeep.ts, 0, 11)) +>U : Symbol(U, Decl(spreadLeftDeep.ts, 0, 13)) +>V : Symbol(V, Decl(spreadLeftDeep.ts, 0, 15)) +>W : Symbol(W, Decl(spreadLeftDeep.ts, 0, 17)) +>t : Symbol(t, Decl(spreadLeftDeep.ts, 0, 20)) +>T : Symbol(T, Decl(spreadLeftDeep.ts, 0, 11)) +>u : Symbol(u, Decl(spreadLeftDeep.ts, 0, 25)) +>U : Symbol(U, Decl(spreadLeftDeep.ts, 0, 13)) +>v : Symbol(v, Decl(spreadLeftDeep.ts, 0, 31)) +>V : Symbol(V, Decl(spreadLeftDeep.ts, 0, 15)) +>w : Symbol(w, Decl(spreadLeftDeep.ts, 0, 37)) +>W : Symbol(W, Decl(spreadLeftDeep.ts, 0, 17)) + + // right-deep structure (T (U (V W)) should get transformed to + // left-deep structure (((T U) V) W) + let x: spread(T, spread(U, spread(V, W))); +>x : Symbol(x, Decl(spreadLeftDeep.ts, 3, 7)) +>T : Symbol(T, Decl(spreadLeftDeep.ts, 0, 11)) +>U : Symbol(U, Decl(spreadLeftDeep.ts, 0, 13)) +>V : Symbol(V, Decl(spreadLeftDeep.ts, 0, 15)) +>W : Symbol(W, Decl(spreadLeftDeep.ts, 0, 17)) + + return x; +>x : Symbol(x, Decl(spreadLeftDeep.ts, 3, 7)) +} + diff --git a/tests/baselines/reference/spreadLeftDeep.types b/tests/baselines/reference/spreadLeftDeep.types new file mode 100644 index 0000000000000..27f2ac731360f --- /dev/null +++ b/tests/baselines/reference/spreadLeftDeep.types @@ -0,0 +1,29 @@ +=== tests/cases/conformance/types/spread/spreadLeftDeep.ts === +function f(t: T, u: U, v: V, w: W) { +>f : (t: T, u: U, v: V, w: W) => spread(spread(spread(T, U), V), W) +>T : T +>U : U +>V : V +>W : W +>t : T +>T : T +>u : U +>U : U +>v : V +>V : V +>w : W +>W : W + + // right-deep structure (T (U (V W)) should get transformed to + // left-deep structure (((T U) V) W) + let x: spread(T, spread(U, spread(V, W))); +>x : spread(spread(spread(T, U), V), W) +>T : T +>U : U +>V : V +>W : W + + return x; +>x : spread(spread(spread(T, U), V), W) +} + diff --git a/tests/cases/compiler/spreadInvalidArgumentType.ts b/tests/cases/compiler/spreadInvalidArgumentType.ts index 2ac6aa921f48c..8e188626200dd 100644 --- a/tests/cases/compiler/spreadInvalidArgumentType.ts +++ b/tests/cases/compiler/spreadInvalidArgumentType.ts @@ -28,21 +28,21 @@ function f(p1: T, p2: T[]) { var e: E; - var o1 = { ...p1 }; // Error, generic type paramterre + var o1 = { ...p1 }; // OK, generic type parameter var o2 = { ...p2 }; // OK - var o3 = { ...t }; // Error, generic type paramter + var o3 = { ...t }; // OK, generic type parameter - var o4 = { ...i }; // Error, index access + var o4 = { ...i }; // OK, index access var o5 = { ...k }; // Error, index - var o6 = { ...mapped_generic }; // Error, generic mapped object type + var o6 = { ...mapped_generic }; // OK, generic mapped object type var o7 = { ...mapped }; // OK, non-generic mapped type - var o8 = { ...union_generic }; // Error, union with generic type parameter - var o9 = { ...union_primitive }; // Error, union with generic type parameter + var o8 = { ...union_generic }; // OK, union with generic type parameter + var o9 = { ...union_primitive }; // OK, union with generic type parameter - var o10 = { ...intersection_generic }; // Error, intersection with generic type parameter - var o11 = { ...intersection_premitive }; // Error, intersection with generic type parameter + var o10 = { ...intersection_generic }; // OK, intersection with generic type parameter + var o11 = { ...intersection_premitive }; // OK, intersection with generic type parameter var o12 = { ...num }; // Error var o13 = { ...str }; // Error @@ -56,4 +56,4 @@ function f(p1: T, p2: T[]) { var o18 = { ...literal_number }; // Error var o19 = { ...e }; // Error, enum -} \ No newline at end of file +} diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index 59b93bdd9e4ad..5e48c151fc20c 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -35,7 +35,10 @@ let getter: { a: number, c: number } = { ...op, c: 7 } getter.a = 12; -// functions result in { } +// null, undefined, object and functions result in { } +let spreadNull = { ...null }; +let spreadUndefined = { ...undefined }; +let spreadNonPrimitive = { ...{}}; let spreadFunc = { ...(function () { }) }; // any results in any @@ -78,5 +81,21 @@ let computedAfter: { a: number, b: string, "at the end": number } = // shortcut syntax let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } -// non primitive -let spreadNonPrimitive = { ...{}}; + +// generics +function f(t: T, u: U): spread(spread(T, U), { id: string }) { + return { ...t, ...u, id: 'id' }; +} + +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +let overlap: { id: string, a: number, b: string } = + f({ a: 1 }, { a: 2, b: 'extra' }) +let overlapConflict: { id:string, a: string } = + f({ a: 1 }, { a: 'mismatch' }) +let overwriteId: { id: string, a: number, c: number, d: string } = + f({ a: 1, id: true }, { c: 1, d: 'no' }) + +class D { m() { }; q = 2; } +let classesAreWrong: spread(spread({ id: string }, C), D) = + f(new C(), new D()) diff --git a/tests/cases/conformance/types/spread/objectSpreadGeneric.ts b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts new file mode 100644 index 0000000000000..44411904787a2 --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts @@ -0,0 +1,72 @@ +function f(t: T, u: U, v: V): void { + let o: spread(spread(T, U), V); + let uus: spread(U, U); + let us: spread(U); + const same: spread(spread(T, U), V) = o; // ok + uus = us; // ok, multiple spreads are equivalent to a single one + us = uus; // ok, multiple spreads are equivalent to a single one + us = u; // ok, type has at least all the properties of the spread + u = us; // error, might be missing a ton of stuff + const reversed: spread(spread(V, U), T) = o; // error, reversed + const reversed2: spread(spread(U, T), V) = o; // error, U and T are still reversed + const missingT: spread(U, V) = o; // error, missing T + const missingU: spread(T, V) = o; // error, missing U + const missingV: spread(T, U) = o; // error, missing V + const atEnd: spread(spread(T, U), { second: string }) = { ...t, ...u, second: 'foo' }; // ok + const atBeginning: spread(spread({ first: string }, T), U) = { first: 'foo', ...t, ...u }; // error, not assignable + + const emptyTarget: { } = { ...t, ...u } // ok + const emptySource: spread(T, U) = { }; // error, {} is not assignable to U (or T) + + // error, { sn?: boolean } ...T ... { sn?: number | string } is not assignable to + // T ... { sn?: number | string | boolean } + let optionalNumber: { sn?: number }; + let optionalString: { sn?: string }; + let optionalBoolean: { sn?: boolean }; + const unionCutoff: spread(T, { sn?: number | string | boolean }) = + { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } + unionCutoff.sn; // ok + const optionalCutoff = { ...t, ...optionalNumber }; // ok + optionalCutoff.sn; // ok + + const interspersed: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string }) = + { first: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable + const interspersedMissingU: spread(spread({ first: string, second: string }, T), { third: string }) = + { first: '1', ...t, second: '2', ...u, third: '3' }; // error, 'U' is missing + const interspersedOrder1: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string , secondsecond: string }) = + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable + const interspersedOrder2: spread(spread({ first: string, second: string, secondsecond: string, third: string }, T), U) = + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable + + + const mismatchFirst: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string }) = + { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable + const mismatchSecond: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string }) = + { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, not assignable + const mismatchLast: spread(spread(spread(spread({ first: string }, T), { second: string }), U), { third: string }) = + { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, not assignable +} + +function indexAccessedTest(t: T, u: U, key1: K, key2: J) { + let k1: spread(keyof T); + let k2: spread(keyof U); + let k3: spread(K); + let k4: spread(J); + k1 = k1; // ok + k2 = k2; // ok + k1 = k2; // error + k2 = k1; // error + k3 = k3; // ok + k4 = k4; // ok + k1 = k3; // error + k3 = k1; // error + k2 = k4; // error + k4 = k2; // error + + let i1: spread(T[K]); + let i2: spread(U[J]); + i1 = i1; // ok + i2 = i2; // ok + i1 = i2; // error + i2 = i1; // error +} diff --git a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts index ae46f2547d54c..fe7f823c4739d 100644 --- a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts +++ b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts @@ -1,3 +1,11 @@ +class C { + a: number; + c: boolean; +} +// index signatures are not allowed in object literals with spread types +let c: spread(C, { b: string, c?: string, [n: number]: string }); +let n: number = c.a; +let s: string = c[12]; interface Indexed { [n: string]: number; a: number; @@ -8,9 +16,13 @@ interface Indexed2 { } let indexed: Indexed; let indexed2: Indexed2; -let i = { ...indexed, b: 11 }; +let i: spread(Indexed, { b: number }); // only indexed has indexer, so i[101]: any i[101]; -let ii = { ...indexed, ...indexed2 }; +let ii: spread(spread(Indexed, Indexed2), { b: boolean, d: number }); // both have indexer, so i[1001]: number | boolean -ii[1001]; +let nb: number | boolean = ii[1001]; + +function f(t: T) { + let i: spread(T, { [n: number]: string }); +} diff --git a/tests/cases/conformance/types/spread/objectSpreadInference.ts b/tests/cases/conformance/types/spread/objectSpreadInference.ts new file mode 100644 index 0000000000000..ebc3b414f5b22 --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadInference.ts @@ -0,0 +1,19 @@ +interface Result { + t: T; + u: U; + v: V; +} +declare function infer(tuv: spread(spread(T, U), { a: V })): { t: T, u: U, v: V }; +declare function infer2(utv: spread(spread(U, { a: V }), T )): { t: T, u: U, v: V }; +function generic(w: W, x: X, y: Y) { + // should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter + return infer({ ...w, ...x, a: y, b: "different type" }); +} +let b: { b: number }; +let c: { c: number }; +// can only infer { t: {}, u: {}, v: {} } +let i1 = infer({ ...b, ...c, a: 12 }); +// can only infer { t: {}, u: {}, v: {} } +let i2 = infer2({ ...b, ...c, a: 12 }); +// can only infer { t: {}, u: {}, v: {} } +let i3 = generic(b, c, { a: 12 }); diff --git a/tests/cases/conformance/types/spread/objectSpreadIntersection.ts b/tests/cases/conformance/types/spread/objectSpreadIntersection.ts new file mode 100644 index 0000000000000..9b7e7a55fd4a4 --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadIntersection.ts @@ -0,0 +1,35 @@ +function iteratedUnionIntersection(t: T, u: U, v: V): void { + let tu: T | U; + let uv: U & V; + let result = { ...tu, ...uv, id: 'foo' }; + let assignable: spread(spread(T | U, U & V), { id: string }) = result; +} +// concrete types work +interface A1 { a: number } +interface A2 { a: string } +interface B1 { b: number } +interface B2 { b: string } +let a12: A1 & A2; +let b12: B1 & B2; +let result = { ...a12, ...b12 }; +let sn: number & string = result.a; +sn = result.b; +let assignable: spread(A1 & A2, B1 & B2) = result; + +function tripleIntersection(t: T, u: U, v: V): void { + let tuv: T & U & V; + let result = { ...tuv, id: 'bar' }; + let assignable: spread(T & U & V, { id: string }) = result; +} +function iteratedDoubleIntersection(t: T, u: U, v: V): void { + let tu: T & U; + let uv: U & V; + let result = { ...tu, ...uv, id: 'baz' }; + let assignable: spread(spread(T & U, U & V), { id: string }) = result; +} +function iteratedIntersectionUnion(t: T, u: U, v: V): void { + let tu: T & U; + let uv: U | V; + let result = { ...tu, ...uv, id: 'qux' }; + let assignable: spread(spread(T & U, U | V), { id: string }) = result; +} diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index c3b42b31aa981..e174b99c5fbab 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -8,9 +8,7 @@ class PrivateOptionalX { class PublicX { public x: number; } -let publicX: PublicX; -let privateOptionalX: PrivateOptionalX; -let o2 = { ...publicX, ...privateOptionalX }; +let o2: spread(PublicX, PrivateOptionalX); let sn: number = o2.x; // error, x is private let optionalString: { sn?: string }; let optionalNumber: { sn?: number }; @@ -20,15 +18,20 @@ let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumbe // assignability as target interface Bool { b: boolean }; interface Str { s: string }; -let spread = { ...{ b: true }, ...{s: "foo" } }; -spread = { s: "foo" }; // error, missing 'b' -let b = { b: false }; +let spread: spread(Bool, Str) = { s: "foo" }; // error, missing 'b' +let b: Bool; spread = b; // error, missing 's' // literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } +// null and undefined are just skipped +let spreadNull = { ...null }; +spreadNull.null; +let spreadUndefined = { ...undefined }; +spreadUndefined.undefined; + // primitives are not allowed let spreadNum = { ...12 }; let spreadSum = { ...1 + 1 }; @@ -42,6 +45,11 @@ spreadStr.charAt(1); // error, no methods either let spreadFunc = { ...function () { } } spreadFunc(); // error, no call signature +// non primitive produces empty object +let obj: object = { a: 123 }; +let spreadObj = { ...obj }; +spreadObj.a; // error 'a' is not in {} + // write-only properties get skipped let setterOnly = { ...{ set b (bad: number) { } } }; setterOnly.b = 12; // error, 'b' does not exist @@ -52,23 +60,14 @@ let c: C = new C() let spreadC = { ...c } spreadC.m(); // error 'm' is not in '{ ... c }' -// non primitive -let obj: object = { a: 123 }; -let spreadObj = { ...obj }; -spreadObj.a; // error 'a' is not in {} +let callableConstructableSpread: spread(PublicX, { (n: number): number, new (p: number) }); +callableConstructableSpread(12); // error, no call signature +new callableConstructableSpread(12); // error, no construct signature -// generics -function f(t: T, u: U) { - return { ...t, ...u, id: 'id' }; -} -function override(initial: U, override: U): U { +function override(initial: U, override: U, t: T, v: V): U { + // { ...T & V } is not assignable to { ...T & U } + let tvs: spread(T & V); + let mistake: spread(T & U) = tvs; + // { ...U } is not assignable to U return { ...initial, ...override }; } -let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = - f({ a: 1, b: 'yes' }, { c: 'no', d: false }) -let overlap: { id: string, a: number, b: string } = - f({ a: 1 }, { a: 2, b: 'extra' }) -let overlapConflict: { id:string, a: string } = - f({ a: 1 }, { a: 'mismatch' }) -let overwriteId: { id: string, a: number, c: number, d: string } = - f({ a: 1, id: true }, { c: 1, d: 'no' }) diff --git a/tests/cases/conformance/types/spread/objectSpreadScenarios.ts b/tests/cases/conformance/types/spread/objectSpreadScenarios.ts new file mode 100644 index 0000000000000..43c1e37dc4d6c --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadScenarios.ts @@ -0,0 +1,17 @@ +interface A1 { a: boolean } +interface B1 { b: number }; +function override(initial: U, override: U): spread(U, U) { + return { ...initial, ...override }; +} +function update(this: { u: spread(U) }, override: U): void { + this.u = { ...this.u, ...override }; +} +function mixin(one: T, two: U): spread(T, U) { + return { ...one, ...two }; +} +let a1: A1 = { a: true }; +let b1: B1 = { b: 101 }; +a1 = override(a1, { a: false }); +let host = { u: a1, update }; +host.update({ a: false }); +let mixed = mixin(a1, b1); diff --git a/tests/cases/conformance/types/spread/objectSpreadUnion.ts b/tests/cases/conformance/types/spread/objectSpreadUnion.ts new file mode 100644 index 0000000000000..deaf1561c35ef --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadUnion.ts @@ -0,0 +1,21 @@ +// concrete types work +interface A1 { a: number } +interface A2 { a: string } +let a12: A1 | A2; +let result = { ...a12 }; +let sn: number | string = result.a; +let assignable: spread(A1 | A2) = result; + +function tripleUnion(t: T, u: U, v: V): void { + let tuv: T | U | V; + let result = { ...tuv, id: 'foo' }; + let expected: spread(T, { id: string }) | spread(U, { id: string }) | spread(V, { id: string }) = result; + let assignable: spread(T | U | V, { id: string }) = result; +} +function iteratedDoubleUnion(t: T, u: U, v: V): void { + let tu: T | U; + let uv: U | V; + let result = { ...tu, ...uv, id: 'bar' }; + let expected: spread(spread(T, U), { id: string }) | spread(spread(T, V), { id: string }) | spread(U, { id: string }) | spread(spread(U, V), { id: string }); + let assignable: spread(spread(T | U, U | V), { id: string }) = result; +} diff --git a/tests/cases/conformance/types/spread/spreadLeftDeep.ts b/tests/cases/conformance/types/spread/spreadLeftDeep.ts new file mode 100644 index 0000000000000..13af958239060 --- /dev/null +++ b/tests/cases/conformance/types/spread/spreadLeftDeep.ts @@ -0,0 +1,6 @@ +function f(t: T, u: U, v: V, w: W) { + // right-deep structure (T (U (V W)) should get transformed to + // left-deep structure (((T U) V) W) + let x: spread(T, spread(U, spread(V, W))); + return x; +} diff --git a/tests/cases/fourslash/findAllRefsForObjectSpread.ts b/tests/cases/fourslash/findAllRefsForObjectSpread.ts index 05c83491f6651..0aea4e1a0cd0c 100644 --- a/tests/cases/fourslash/findAllRefsForObjectSpread.ts +++ b/tests/cases/fourslash/findAllRefsForObjectSpread.ts @@ -2,13 +2,18 @@ ////interface A1 { [|a|]: string }; ////interface A2 { [|a|]?: number }; -////let a1: A1; -////let a2: A2; -////let a12 = { ...a1, ...a2 }; -////a12.[|a|]; +////interface A3 { [|a|]?: boolean }; +////let a123: spread(spread(A1, A2), A3); +////a123.[|a|]; const ranges = test.ranges(); + // members of spread types only refer to themselves and the resulting property -verify.referencesOf(ranges[0], [ranges[0], ranges[2]]); -verify.referencesOf(ranges[1], [ranges[1], ranges[2]]); +verifyReferencesOfIndices(ranges, 0, [0, 3]); +verifyReferencesOfIndices(ranges, 1, [1, 3]); +verifyReferencesOfIndices(ranges, 2, [2, 3]); // but the resulting property refers to everything -verify.referencesOf(ranges[2], ranges); +verifyReferencesOfIndices(ranges, 3, [0, 1, 2, 3]); + +function verifyReferencesOfIndices(ranges: FourSlashInterface.Range[], source: number, ns: number[]) { + verify.referencesOf(ranges[source], ns.map(n => ranges[n])); +} diff --git a/tests/cases/fourslash/goToDefinitionObjectSpread.ts b/tests/cases/fourslash/goToDefinitionObjectSpread.ts index b23d0a8044832..f4d0a089d8c07 100644 --- a/tests/cases/fourslash/goToDefinitionObjectSpread.ts +++ b/tests/cases/fourslash/goToDefinitionObjectSpread.ts @@ -2,8 +2,6 @@ ////interface A1 { /*1*/a: number }; ////interface A2 { /*2*/a?: number }; -////let a1: A1; -////let a2: A2; -////let a12 = { ...a1, ...a2 }; +////let a12: spread(A1, A2); ////a12.a/*3*/; verify.goToDefinition('3', [ '1', '2' ]); diff --git a/tests/cases/fourslash/renameObjectSpread.ts b/tests/cases/fourslash/renameObjectSpread.ts index f56c22dd42f3d..b09bd5ca5eb0c 100644 --- a/tests/cases/fourslash/renameObjectSpread.ts +++ b/tests/cases/fourslash/renameObjectSpread.ts @@ -2,9 +2,7 @@ ////interface A1 { [|a|]: number }; ////interface A2 { [|a|]?: number }; -////let a1: A1; -////let a2: A2; -////let a12 = { ...a1, ...a2 }; +////let a12: spread(A1, A2); ////a12.[|a|]; const ranges = test.ranges(); verify.assertHasRanges(ranges);