From d775f0f569226d3cbee44ebdc982989ddc527549 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Wed, 16 Nov 2016 11:54:02 -0800 Subject: [PATCH 01/26] Improve diagnostic messages for imported helpers --- src/compiler/binder.ts | 23 ---- src/compiler/checker.ts | 122 ++++++++++-------- src/compiler/diagnosticMessages.json | 8 ++ src/compiler/types.ts | 45 ++++--- src/compiler/utilities.ts | 4 + .../importHelpersNoHelpers.errors.txt | 32 +++-- .../importHelpersNoModule.errors.txt | 7 +- 7 files changed, 133 insertions(+), 108 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 1afe51db0218b..4bcf5b929a8d7 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -518,7 +518,6 @@ namespace ts { hasExplicitReturn = false; bindChildren(node); // Reset all reachability check related flags on node (for incremental scenarios) - // Reset all emit helper flags on node (for incremental scenarios) node.flags &= ~NodeFlags.ReachabilityAndEmitFlags; if (!(currentFlow.flags & FlowFlags.Unreachable) && containerFlags & ContainerFlags.IsFunctionLike && nodeIsPresent((node).body)) { node.flags |= NodeFlags.HasImplicitReturn; @@ -1950,9 +1949,6 @@ namespace ts { return bindParameter(node); case SyntaxKind.VariableDeclaration: case SyntaxKind.BindingElement: - if ((node as BindingElement).dotDotDotToken && node.parent.kind === SyntaxKind.ObjectBindingPattern) { - emitFlags |= NodeFlags.HasRestAttribute; - } return bindVariableDeclarationOrBindingElement(node); case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: @@ -1980,7 +1976,6 @@ namespace ts { } root = root.parent; } - emitFlags |= hasRest ? NodeFlags.HasRestAttribute : NodeFlags.HasSpreadAttribute; return; case SyntaxKind.CallSignature: @@ -2236,15 +2231,6 @@ namespace ts { } function bindClassLikeDeclaration(node: ClassLikeDeclaration) { - if (!isDeclarationFile(file) && !isInAmbientContext(node)) { - if (getClassExtendsHeritageClauseElement(node) !== undefined) { - emitFlags |= NodeFlags.HasClassExtends; - } - if (nodeIsDecorated(node)) { - emitFlags |= NodeFlags.HasDecorators; - } - } - if (node.kind === SyntaxKind.ClassDeclaration) { bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes); } @@ -2314,12 +2300,6 @@ namespace ts { } function bindParameter(node: ParameterDeclaration) { - if (!isDeclarationFile(file) && - !isInAmbientContext(node) && - nodeIsDecorated(node)) { - emitFlags |= (NodeFlags.HasDecorators | NodeFlags.HasParamDecorators); - } - if (inStrictMode) { // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a // strict mode FunctionLikeDeclaration or FunctionExpression(13.1) @@ -2377,9 +2357,6 @@ namespace ts { if (isAsyncFunctionLike(node)) { emitFlags |= NodeFlags.HasAsyncFunctions; } - if (nodeIsDecorated(node)) { - emitFlags |= NodeFlags.HasDecorators; - } } if (currentFlow && isObjectLiteralOrClassExpressionMethod(node)) { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7132aedb32499..d9ce0fc95ddd5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -38,6 +38,8 @@ namespace ts { // is because diagnostics can be quite expensive, and we want to allow hosts to bail out if // they no longer need the information (for example, if the user started editing again). let cancellationToken: CancellationToken; + let requestedExternalEmitHelpers: ExternalEmitHelpers; + let externalHelpersModule: Symbol; const Symbol = objectAllocator.getSymbolConstructor(); const Type = objectAllocator.getTypeConstructor(); @@ -11272,6 +11274,9 @@ namespace ts { member = prop; } else if (memberDecl.kind === SyntaxKind.SpreadAssignment) { + if (languageVersion < ScriptTarget.ESNext) { + checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign); + } if (propertiesArray.length > 0) { spread = getSpreadType(spread, createObjectLiteralType(), /*isFromObjectLiteral*/ true); propertiesArray = []; @@ -11459,6 +11464,9 @@ namespace ts { } function checkJsxSpreadAttribute(node: JsxSpreadAttribute, elementAttributesType: Type, nameTable: Map) { + if (compilerOptions.jsx === JsxEmit.React) { + checkExternalEmitHelpers(node, ExternalEmitHelpers.Assign); + } const type = checkExpression(node.expression); const props = getPropertiesOfType(type); for (const prop of props) { @@ -14223,6 +14231,9 @@ namespace ts { } } else if (property.kind === SyntaxKind.SpreadAssignment) { + if (languageVersion < ScriptTarget.ESNext) { + checkExternalEmitHelpers(property, ExternalEmitHelpers.Rest); + } checkReferenceExpression(property.expression, Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access); } else { @@ -15107,6 +15118,13 @@ namespace ts { checkGrammarFunctionLikeDeclaration(node); } + if (isAsyncFunctionLike(node) && languageVersion < ScriptTarget.ES2017) { + checkExternalEmitHelpers(node, ExternalEmitHelpers.Awaiter); + if (languageVersion < ScriptTarget.ES2015) { + checkExternalEmitHelpers(node, ExternalEmitHelpers.Generator); + } + } + checkTypeParameters(node.typeParameters); forEach(node.parameters, checkParameter); @@ -16242,7 +16260,15 @@ namespace ts { error(node, Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_to_remove_this_warning); } + const firstDecorator = node.decorators[0]; + checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.Decorate); + if (node.kind === SyntaxKind.Parameter) { + checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.Param); + } + if (compilerOptions.emitDecoratorMetadata) { + checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.Metadata); + // we only need to perform these checks if we are emitting serialized type metadata for the target of a decorator. switch (node.kind) { case SyntaxKind.ClassDeclaration: @@ -16629,7 +16655,7 @@ namespace ts { } function checkCollisionWithGlobalPromiseInGeneratedCode(node: Node, name: Identifier): void { - if (!needCollisionCheckForIdentifier(node, name, "Promise")) { + if (languageVersion >= ScriptTarget.ES2017 || !needCollisionCheckForIdentifier(node, name, "Promise")) { return; } @@ -16806,6 +16832,9 @@ namespace ts { } if (node.kind === SyntaxKind.BindingElement) { + if (node.parent.kind === SyntaxKind.ObjectBindingPattern && languageVersion < ScriptTarget.ESNext) { + checkExternalEmitHelpers(node, ExternalEmitHelpers.Rest); + } // check computed properties inside property names of binding elements if (node.propertyName && node.propertyName.kind === SyntaxKind.ComputedPropertyName) { checkComputedPropertyName(node.propertyName); @@ -17724,6 +17753,10 @@ namespace ts { const baseTypeNode = getClassExtendsHeritageClauseElement(node); if (baseTypeNode) { + if (languageVersion < ScriptTarget.ES2015) { + checkExternalEmitHelpers(baseTypeNode.parent, ExternalEmitHelpers.Extends); + } + const baseTypes = getBaseTypes(type); if (baseTypes.length && produceDiagnostics) { const baseType = baseTypes[0]; @@ -20164,8 +20197,6 @@ namespace ts { // Initialize global symbol table let augmentations: LiteralExpression[][]; - let requestedExternalEmitHelpers: NodeFlags = 0; - let firstFileRequestingExternalHelpers: SourceFile; for (const file of host.getSourceFiles()) { if (!isExternalOrCommonJsModule(file)) { mergeSymbolTable(globals, file.locals); @@ -20185,15 +20216,6 @@ namespace ts { } } } - if ((compilerOptions.isolatedModules || isExternalModule(file)) && !file.isDeclarationFile) { - const fileRequestedExternalEmitHelpers = file.flags & NodeFlags.EmitHelperFlags; - if (fileRequestedExternalEmitHelpers) { - requestedExternalEmitHelpers |= fileRequestedExternalEmitHelpers; - if (firstFileRequestingExternalHelpers === undefined) { - firstFileRequestingExternalHelpers = file; - } - } - } } if (augmentations) { @@ -20259,57 +20281,51 @@ namespace ts { const symbol = getGlobalSymbol("ReadonlyArray", SymbolFlags.Type, /*diagnostic*/ undefined); globalReadonlyArrayType = symbol && getTypeOfGlobalSymbol(symbol, /*arity*/ 1); anyReadonlyArrayType = globalReadonlyArrayType ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [anyType]) : anyArrayType; + } - // If we have specified that we are importing helpers, we should report global - // errors if we cannot resolve the helpers external module, or if it does not have - // the necessary helpers exported. - if (compilerOptions.importHelpers && firstFileRequestingExternalHelpers) { - // Find the first reference to the helpers module. - const helpersModule = resolveExternalModule( - firstFileRequestingExternalHelpers, - externalHelpersModuleNameText, - Diagnostics.Cannot_find_module_0, - /*errorNode*/ undefined); - - // If we found the module, report errors if it does not have the necessary exports. - if (helpersModule) { - const exports = helpersModule.exports; - if (requestedExternalEmitHelpers & NodeFlags.HasClassExtends && languageVersion < ScriptTarget.ES2015) { - verifyHelperSymbol(exports, "__extends", SymbolFlags.Value); - } - if (requestedExternalEmitHelpers & NodeFlags.HasSpreadAttribute && - (languageVersion < ScriptTarget.ESNext || compilerOptions.jsx === JsxEmit.React)) { - verifyHelperSymbol(exports, "__assign", SymbolFlags.Value); - } - if (languageVersion < ScriptTarget.ESNext && requestedExternalEmitHelpers & NodeFlags.HasRestAttribute) { - verifyHelperSymbol(exports, "__rest", SymbolFlags.Value); - } - if (requestedExternalEmitHelpers & NodeFlags.HasDecorators) { - verifyHelperSymbol(exports, "__decorate", SymbolFlags.Value); - if (compilerOptions.emitDecoratorMetadata) { - verifyHelperSymbol(exports, "__metadata", SymbolFlags.Value); - } - } - if (requestedExternalEmitHelpers & NodeFlags.HasParamDecorators) { - verifyHelperSymbol(exports, "__param", SymbolFlags.Value); - } - if (requestedExternalEmitHelpers & NodeFlags.HasAsyncFunctions) { - verifyHelperSymbol(exports, "__awaiter", SymbolFlags.Value); - if (languageVersion < ScriptTarget.ES2015) { - verifyHelperSymbol(exports, "__generator", SymbolFlags.Value); + function checkExternalEmitHelpers(location: Node, helpers: ExternalEmitHelpers) { + if ((requestedExternalEmitHelpers & helpers) !== helpers && compilerOptions.importHelpers) { + const sourceFile = getSourceFileOfNode(location); + if (isEffectiveExternalModule(sourceFile, compilerOptions)) { + const helpersModule = resolveHelpersModule(sourceFile, location); + if (helpersModule !== unknownSymbol) { + const uncheckedHelpers = helpers & ~requestedExternalEmitHelpers; + for (let helper = ExternalEmitHelpers.FirstEmitHelper; helper <= ExternalEmitHelpers.LastEmitHelper; helper <<= 1) { + if (uncheckedHelpers & helper) { + const name = getHelperName(helper); + const symbol = getSymbol(helpersModule.exports, escapeIdentifier(name), SymbolFlags.Value); + if (!symbol) { + error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_but_module_0_has_no_exported_member_1, externalHelpersModuleNameText, name); + } + } } } + requestedExternalEmitHelpers |= helpers; } } } - function verifyHelperSymbol(symbols: SymbolTable, name: string, meaning: SymbolFlags) { - const symbol = getSymbol(symbols, escapeIdentifier(name), meaning); - if (!symbol) { - error(/*location*/ undefined, Diagnostics.Module_0_has_no_exported_member_1, externalHelpersModuleNameText, name); + function getHelperName(helper: ExternalEmitHelpers) { + switch (helper) { + case ExternalEmitHelpers.Extends: return "__extends"; + case ExternalEmitHelpers.Assign: return "__assign"; + case ExternalEmitHelpers.Rest: return "__rest"; + case ExternalEmitHelpers.Decorate: return "__decorate"; + case ExternalEmitHelpers.Metadata: return "__metadata"; + case ExternalEmitHelpers.Param: return "__param"; + case ExternalEmitHelpers.Awaiter: return "__awaiter"; + case ExternalEmitHelpers.Generator: return "__generator"; } } + function resolveHelpersModule(node: SourceFile, errorNode: Node) { + if (!externalHelpersModule) { + externalHelpersModule = resolveExternalModule(node, externalHelpersModuleNameText, Diagnostics.This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found, errorNode) || unknownSymbol; + } + return externalHelpersModule; + } + + function createInstantiatedPromiseLikeType(): ObjectType { const promiseLikeType = getGlobalPromiseLikeType(); if (promiseLikeType !== emptyGenericType) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a163a3bb641e1..bb8f50c879cf8 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1023,6 +1023,10 @@ "category": "Error", "code": 2342 }, + "This syntax requires an imported helper named '{1}', but module '{0}' has no exported member '{1}'.": { + "category": "Error", + "code": 2343 + }, "Type '{0}' does not satisfy the constraint '{1}'.": { "category": "Error", "code": 2344 @@ -1063,6 +1067,10 @@ "category": "Error", "code": 2353 }, + "This syntax requires an imported helper but module '{0}' cannot be found.": { + "category": "Error", + "code": 2354 + }, "A function whose declared type is neither 'void' nor 'any' must return a value.": { "category": "Error", "code": 2355 diff --git a/src/compiler/types.ts b/src/compiler/types.ts index af46cb2173cb9..9330c54fa7652 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -417,26 +417,20 @@ namespace ts { HasImplicitReturn = 1 << 7, // If function implicitly returns on one of codepaths (initialized by binding) HasExplicitReturn = 1 << 8, // If function has explicit reachable return on one of codepaths (initialized by binding) GlobalAugmentation = 1 << 9, // Set if module declaration is an augmentation for the global scope - HasClassExtends = 1 << 10, // If the file has a non-ambient class with an extends clause in ES5 or lower (initialized by binding) - HasDecorators = 1 << 11, // If the file has decorators (initialized by binding) - HasParamDecorators = 1 << 12, // If the file has parameter decorators (initialized by binding) - HasAsyncFunctions = 1 << 13, // If the file has async functions (initialized by binding) - HasSpreadAttribute = 1 << 14, // If the file as JSX spread attributes (initialized by binding) - HasRestAttribute = 1 << 15, // If the file has object destructure elements - DisallowInContext = 1 << 16, // If node was parsed in a context where 'in-expressions' are not allowed - YieldContext = 1 << 17, // If node was parsed in the 'yield' context created when parsing a generator - DecoratorContext = 1 << 18, // If node was parsed as part of a decorator - AwaitContext = 1 << 19, // If node was parsed in the 'await' context created when parsing an async function - ThisNodeHasError = 1 << 20, // If the parser encountered an error when parsing the code that created this node - JavaScriptFile = 1 << 21, // If node was parsed in a JavaScript - ThisNodeOrAnySubNodesHasError = 1 << 22, // If this node or any of its children had an error - HasAggregatedChildData = 1 << 23, // If we've computed data from children and cached it in this node + HasAsyncFunctions = 1 << 10, // If the file has async functions (initialized by binding) + DisallowInContext = 1 << 11, // If node was parsed in a context where 'in-expressions' are not allowed + YieldContext = 1 << 12, // If node was parsed in the 'yield' context created when parsing a generator + DecoratorContext = 1 << 13, // If node was parsed as part of a decorator + AwaitContext = 1 << 14, // If node was parsed in the 'await' context created when parsing an async function + ThisNodeHasError = 1 << 15, // If the parser encountered an error when parsing the code that created this node + JavaScriptFile = 1 << 16, // If node was parsed in a JavaScript + ThisNodeOrAnySubNodesHasError = 1 << 17, // If this node or any of its children had an error + HasAggregatedChildData = 1 << 18, // If we've computed data from children and cached it in this node BlockScoped = Let | Const, ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn, - EmitHelperFlags = HasClassExtends | HasDecorators | HasParamDecorators | HasAsyncFunctions | HasSpreadAttribute | HasRestAttribute, - ReachabilityAndEmitFlags = ReachabilityCheckFlags | EmitHelperFlags, + ReachabilityAndEmitFlags = ReachabilityCheckFlags | HasAsyncFunctions, // Parsing context flags ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile, @@ -3687,6 +3681,25 @@ namespace ts { readonly priority?: number; // Helpers with a higher priority are emitted earlier than other helpers on the node. } + /** + * Used by the checker, this enum keeps track of external emit helpers that should be type + * checked. + */ + /* @internal */ + export const enum ExternalEmitHelpers { + Extends = 1 << 0, // __extends (used by the ES2015 class transformation) + Assign = 1 << 1, // __assign (used by Jsx and ESNext object spread transformations) + Rest = 1 << 2, // __rest (used by ESNext object rest transformation) + Decorate = 1 << 3, // __decorate (used by TypeScript decorators transformation) + Metadata = 1 << 4, // __metadata (used by TypeScript decorators transformation) + Param = 1 << 5, // __param (used by TypeScript decorators transformation) + Awaiter = 1 << 6, // __awaiter (used by ES2017 async functions transformation) + Generator = 1 << 7, // __generator (used by ES2015 generator transformation) + + FirstEmitHelper = Extends, + LastEmitHelper = Generator + } + /* @internal */ export const enum EmitContext { SourceFile, // Emitting a SourceFile diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index bfabb3b1e4a9d..e5e42f93a4b6c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -423,6 +423,10 @@ namespace ts { return false; } + export function isEffectiveExternalModule(node: SourceFile, compilerOptions: CompilerOptions) { + return isExternalModule(node) || compilerOptions.isolatedModules; + } + export function isBlockScope(node: Node, parentNode: Node) { switch (node.kind) { case SyntaxKind.SourceFile: diff --git a/tests/baselines/reference/importHelpersNoHelpers.errors.txt b/tests/baselines/reference/importHelpersNoHelpers.errors.txt index fa9a935c8d811..a0c089a9ddc26 100644 --- a/tests/baselines/reference/importHelpersNoHelpers.errors.txt +++ b/tests/baselines/reference/importHelpersNoHelpers.errors.txt @@ -1,32 +1,38 @@ -error TS2305: Module 'tslib' has no exported member '__assign'. -error TS2305: Module 'tslib' has no exported member '__decorate'. -error TS2305: Module 'tslib' has no exported member '__extends'. -error TS2305: Module 'tslib' has no exported member '__metadata'. -error TS2305: Module 'tslib' has no exported member '__param'. -error TS2305: Module 'tslib' has no exported member '__rest'. +tests/cases/compiler/external.ts(2,16): error TS2343: This syntax requires an imported helper named '__extends', but module 'tslib' has no exported member '__extends'. +tests/cases/compiler/external.ts(6,1): error TS2343: This syntax requires an imported helper named '__decorate', but module 'tslib' has no exported member '__decorate'. +tests/cases/compiler/external.ts(6,1): error TS2343: This syntax requires an imported helper named '__metadata', but module 'tslib' has no exported member '__metadata'. +tests/cases/compiler/external.ts(8,12): error TS2343: This syntax requires an imported helper named '__param', but module 'tslib' has no exported member '__param'. +tests/cases/compiler/external.ts(13,13): error TS2343: This syntax requires an imported helper named '__assign', but module 'tslib' has no exported member '__assign'. +tests/cases/compiler/external.ts(14,12): error TS2343: This syntax requires an imported helper named '__rest', but module 'tslib' has no exported member '__rest'. -!!! error TS2305: Module 'tslib' has no exported member '__assign'. -!!! error TS2305: Module 'tslib' has no exported member '__decorate'. -!!! error TS2305: Module 'tslib' has no exported member '__extends'. -!!! error TS2305: Module 'tslib' has no exported member '__metadata'. -!!! error TS2305: Module 'tslib' has no exported member '__param'. -!!! error TS2305: Module 'tslib' has no exported member '__rest'. -==== tests/cases/compiler/external.ts (0 errors) ==== +==== tests/cases/compiler/external.ts (6 errors) ==== export class A { } export class B extends A { } + ~~~~~~~~~ +!!! error TS2343: This syntax requires an imported helper named '__extends', but module 'tslib' has no exported member '__extends'. declare var dec: any; @dec + ~~~~ +!!! error TS2343: This syntax requires an imported helper named '__decorate', but module 'tslib' has no exported member '__decorate'. + ~~~~ +!!! error TS2343: This syntax requires an imported helper named '__metadata', but module 'tslib' has no exported member '__metadata'. class C { method(@dec x: number) { + ~~~~ +!!! error TS2343: This syntax requires an imported helper named '__param', but module 'tslib' has no exported member '__param'. } } const o = { a: 1 }; const y = { ...o }; + ~~~~ +!!! error TS2343: This syntax requires an imported helper named '__assign', but module 'tslib' has no exported member '__assign'. const { ...x } = y; + ~ +!!! error TS2343: This syntax requires an imported helper named '__rest', but module 'tslib' has no exported member '__rest'. ==== tests/cases/compiler/script.ts (0 errors) ==== class A { } diff --git a/tests/baselines/reference/importHelpersNoModule.errors.txt b/tests/baselines/reference/importHelpersNoModule.errors.txt index d59fd0537ca5d..b6786ec363552 100644 --- a/tests/baselines/reference/importHelpersNoModule.errors.txt +++ b/tests/baselines/reference/importHelpersNoModule.errors.txt @@ -1,10 +1,11 @@ -error TS2307: Cannot find module 'tslib'. +tests/cases/compiler/external.ts(2,16): error TS2354: This syntax requires an imported helper but module 'tslib' cannot be found. -!!! error TS2307: Cannot find module 'tslib'. -==== tests/cases/compiler/external.ts (0 errors) ==== +==== tests/cases/compiler/external.ts (1 errors) ==== export class A { } export class B extends A { } + ~~~~~~~~~ +!!! error TS2354: This syntax requires an imported helper but module 'tslib' cannot be found. declare var dec: any; From f2e30f66936d4e4192aa0bb32049d7e64db10f59 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 00:04:20 -0800 Subject: [PATCH 02/26] Allow union and intersection as targets for object spread and rest, and distribute spread&rest over unions --- src/compiler/checker.ts | 31 ++++- .../restIntersectionOrIntersection.js | 29 +++++ .../restIntersectionOrIntersection.symbols | 38 ++++++ .../restIntersectionOrIntersection.types | 38 ++++++ .../restInvalidArgumentType.errors.txt | 110 +++++++++++++++++ .../reference/restInvalidArgumentType.js | 115 ++++++++++++++++++ .../baselines/reference/spreadIntersection.js | 23 ++++ .../reference/spreadIntersection.symbols | 26 ++++ .../reference/spreadIntersection.types | 29 +++++ .../spreadInvalidArgumentType.errors.txt | 110 +++++++++++++++++ .../reference/spreadInvalidArgumentType.js | 114 +++++++++++++++++ tests/baselines/reference/spreadUnion.js | 28 +++++ tests/baselines/reference/spreadUnion.symbols | 38 ++++++ tests/baselines/reference/spreadUnion.types | 42 +++++++ .../restIntersectionOrIntersection.ts | 10 ++ .../cases/compiler/restInvalidArgumentType.ts | 59 +++++++++ tests/cases/compiler/spreadIntersection.ts | 7 ++ .../compiler/spreadInvalidArgumentType.ts | 59 +++++++++ tests/cases/compiler/spreadUnion.ts | 10 ++ 19 files changed, 911 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/restIntersectionOrIntersection.js create mode 100644 tests/baselines/reference/restIntersectionOrIntersection.symbols create mode 100644 tests/baselines/reference/restIntersectionOrIntersection.types create mode 100644 tests/baselines/reference/restInvalidArgumentType.errors.txt create mode 100644 tests/baselines/reference/restInvalidArgumentType.js create mode 100644 tests/baselines/reference/spreadIntersection.js create mode 100644 tests/baselines/reference/spreadIntersection.symbols create mode 100644 tests/baselines/reference/spreadIntersection.types create mode 100644 tests/baselines/reference/spreadInvalidArgumentType.errors.txt create mode 100644 tests/baselines/reference/spreadInvalidArgumentType.js create mode 100644 tests/baselines/reference/spreadUnion.js create mode 100644 tests/baselines/reference/spreadUnion.symbols create mode 100644 tests/baselines/reference/spreadUnion.types create mode 100644 tests/cases/compiler/restIntersectionOrIntersection.ts create mode 100644 tests/cases/compiler/restInvalidArgumentType.ts create mode 100644 tests/cases/compiler/spreadIntersection.ts create mode 100644 tests/cases/compiler/spreadInvalidArgumentType.ts create mode 100644 tests/cases/compiler/spreadUnion.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 527735a3b0f4a..e937f6d9b973d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3054,7 +3054,10 @@ namespace ts { } function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type { - Debug.assert(!!(source.flags & TypeFlags.Object), "Rest types only support object types right now."); + if (source.flags & TypeFlags.Union) { + return getUnionType(map((source).types, t => getRestType(t, properties, symbol))); + } + const members = createMap(); const names = createMap(); for (const name of properties) { @@ -3095,7 +3098,7 @@ namespace ts { let type: Type; if (pattern.kind === SyntaxKind.ObjectBindingPattern) { if (declaration.dotDotDotToken) { - if (!(parentType.flags & TypeFlags.Object)) { + if (isInvalidValidSpreadType(parentType)) { error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); return unknownType; } @@ -6102,11 +6105,19 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, isFromObjectLiteral: boolean): ResolvedType | IntrinsicType { - Debug.assert(!!(left.flags & (TypeFlags.Object | TypeFlags.Any)) && !!(right.flags & (TypeFlags.Object | TypeFlags.Any)), "Only object types may be spread."); + function getSpreadType(left: Type, right: Type, isFromObjectLiteral: boolean): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } + + if (left.flags & TypeFlags.Union) { + return getUnionType(map((left).types, t => getSpreadType(t, right, isFromObjectLiteral))); + } + + if (right.flags & TypeFlags.Union) { + return getUnionType(map((right).types, t => getSpreadType(left, t, isFromObjectLiteral))); + } + const members = createMap(); const skippedPrivateMembers = createMap(); let stringIndexInfo: IndexInfo; @@ -11438,7 +11449,7 @@ namespace ts { typeFlags = 0; } const type = checkExpression((memberDecl as SpreadAssignment).expression); - if (!(type.flags & (TypeFlags.Object | TypeFlags.Any))) { + if (!(type.flags & TypeFlags.Any) && isInvalidValidSpreadType(type)) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } @@ -11516,6 +11527,16 @@ namespace ts { } } + function isInvalidValidSpreadType(type: Type): boolean { + if (type.flags & TypeFlags.Object) { + return isGenericMappedType(type); + } + else if (type.flags & TypeFlags.UnionOrIntersection) { + return forEach((type).types, isInvalidValidSpreadType); + } + return true; + } + function checkJsxSelfClosingElement(node: JsxSelfClosingElement) { checkJsxOpeningLikeElement(node); return jsxElementType || anyType; diff --git a/tests/baselines/reference/restIntersectionOrIntersection.js b/tests/baselines/reference/restIntersectionOrIntersection.js new file mode 100644 index 0000000000000..a60a5acbd9328 --- /dev/null +++ b/tests/baselines/reference/restIntersectionOrIntersection.js @@ -0,0 +1,29 @@ +//// [restIntersectionOrIntersection.ts] +var intersection: { x: number, y: number } & { w: string, z: string }; +var union: { a: number, c: boolean } | { a: string, b: string }; + + +var rest1: { y: number, w: string, z: string }; +var {x, ...rest1 } = intersection; + +var rest2: { c: boolean } | { b: string }; +var {a, ...rest2 } = union; + + + +//// [restIntersectionOrIntersection.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +var intersection; +var union; +var rest1; +var x = intersection.x, rest1 = __rest(intersection, ["x"]); +var rest2; +var a = union.a, rest2 = __rest(union, ["a"]); diff --git a/tests/baselines/reference/restIntersectionOrIntersection.symbols b/tests/baselines/reference/restIntersectionOrIntersection.symbols new file mode 100644 index 0000000000000..f2eb4f16014f0 --- /dev/null +++ b/tests/baselines/reference/restIntersectionOrIntersection.symbols @@ -0,0 +1,38 @@ +=== tests/cases/compiler/restIntersectionOrIntersection.ts === +var intersection: { x: number, y: number } & { w: string, z: string }; +>intersection : Symbol(intersection, Decl(restIntersectionOrIntersection.ts, 0, 3)) +>x : Symbol(x, Decl(restIntersectionOrIntersection.ts, 0, 19)) +>y : Symbol(y, Decl(restIntersectionOrIntersection.ts, 0, 30)) +>w : Symbol(w, Decl(restIntersectionOrIntersection.ts, 0, 46)) +>z : Symbol(z, Decl(restIntersectionOrIntersection.ts, 0, 57)) + +var union: { a: number, c: boolean } | { a: string, b: string }; +>union : Symbol(union, Decl(restIntersectionOrIntersection.ts, 1, 3)) +>a : Symbol(a, Decl(restIntersectionOrIntersection.ts, 1, 12)) +>c : Symbol(c, Decl(restIntersectionOrIntersection.ts, 1, 23)) +>a : Symbol(a, Decl(restIntersectionOrIntersection.ts, 1, 40)) +>b : Symbol(b, Decl(restIntersectionOrIntersection.ts, 1, 51)) + + +var rest1: { y: number, w: string, z: string }; +>rest1 : Symbol(rest1, Decl(restIntersectionOrIntersection.ts, 4, 3), Decl(restIntersectionOrIntersection.ts, 5, 7)) +>y : Symbol(y, Decl(restIntersectionOrIntersection.ts, 4, 12)) +>w : Symbol(w, Decl(restIntersectionOrIntersection.ts, 4, 23)) +>z : Symbol(z, Decl(restIntersectionOrIntersection.ts, 4, 34)) + +var {x, ...rest1 } = intersection; +>x : Symbol(x, Decl(restIntersectionOrIntersection.ts, 5, 5)) +>rest1 : Symbol(rest1, Decl(restIntersectionOrIntersection.ts, 4, 3), Decl(restIntersectionOrIntersection.ts, 5, 7)) +>intersection : Symbol(intersection, Decl(restIntersectionOrIntersection.ts, 0, 3)) + +var rest2: { c: boolean } | { b: string }; +>rest2 : Symbol(rest2, Decl(restIntersectionOrIntersection.ts, 7, 3), Decl(restIntersectionOrIntersection.ts, 8, 7)) +>c : Symbol(c, Decl(restIntersectionOrIntersection.ts, 7, 12)) +>b : Symbol(b, Decl(restIntersectionOrIntersection.ts, 7, 29)) + +var {a, ...rest2 } = union; +>a : Symbol(a, Decl(restIntersectionOrIntersection.ts, 8, 5)) +>rest2 : Symbol(rest2, Decl(restIntersectionOrIntersection.ts, 7, 3), Decl(restIntersectionOrIntersection.ts, 8, 7)) +>union : Symbol(union, Decl(restIntersectionOrIntersection.ts, 1, 3)) + + diff --git a/tests/baselines/reference/restIntersectionOrIntersection.types b/tests/baselines/reference/restIntersectionOrIntersection.types new file mode 100644 index 0000000000000..c87769ff3ccdf --- /dev/null +++ b/tests/baselines/reference/restIntersectionOrIntersection.types @@ -0,0 +1,38 @@ +=== tests/cases/compiler/restIntersectionOrIntersection.ts === +var intersection: { x: number, y: number } & { w: string, z: string }; +>intersection : { x: number; y: number; } & { w: string; z: string; } +>x : number +>y : number +>w : string +>z : string + +var union: { a: number, c: boolean } | { a: string, b: string }; +>union : { a: number; c: boolean; } | { a: string; b: string; } +>a : number +>c : boolean +>a : string +>b : string + + +var rest1: { y: number, w: string, z: string }; +>rest1 : { y: number; w: string; z: string; } +>y : number +>w : string +>z : string + +var {x, ...rest1 } = intersection; +>x : number +>rest1 : { y: number; w: string; z: string; } +>intersection : { x: number; y: number; } & { w: string; z: string; } + +var rest2: { c: boolean } | { b: string }; +>rest2 : { c: boolean; } | { b: string; } +>c : boolean +>b : string + +var {a, ...rest2 } = union; +>a : string | number +>rest2 : { c: boolean; } | { b: string; } +>union : { a: number; c: boolean; } | { a: string; b: string; } + + diff --git a/tests/baselines/reference/restInvalidArgumentType.errors.txt b/tests/baselines/reference/restInvalidArgumentType.errors.txt new file mode 100644 index 0000000000000..e7cf1ba6f9fc1 --- /dev/null +++ b/tests/baselines/reference/restInvalidArgumentType.errors.txt @@ -0,0 +1,110 @@ +tests/cases/compiler/restInvalidArgumentType.ts(31,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(33,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(35,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(36,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(38,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(41,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(42,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(44,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(45,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(47,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(48,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(50,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(51,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(55,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(56,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(58,13): error TS2700: Rest types may only be created from object types. + + +==== tests/cases/compiler/restInvalidArgumentType.ts (16 errors) ==== + enum E { v1, v2 }; + + function f(p1: T, p2: T[]) { + var t: T; + + var i: T["b"]; + var k: keyof T; + + var mapped_generic: {[P in keyof T]: T[P]}; + var mapped: {[P in "b"]: T[P]}; + + var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; + + var intersection_generic: T & { a: number }; + var intersection_premitive: { a: number } | string; + + var num: number; + var str: number; + + var u: undefined; + var n: null; + + var a: any; + + var literal_string: "string"; + var literal_number: 42; + + var e: E; + + var {...r1} = p1; // Error, generic type paramterre + ~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r2} = p2; // OK + var {...r3} = t; // Error, generic type paramter + ~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r4} = i; // Error, index access + ~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r5} = k; // Error, index + ~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r6} = mapped_generic; // Error, generic mapped object type + ~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r7} = mapped; // OK, non-generic mapped type + + var {...r8} = union_generic; // Error, union with generic type parameter + ~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r9} = union_primitive; // Error, union with generic type parameter + ~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r10} = intersection_generic; // Error, intersection with generic type parameter + ~~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r11} = intersection_premitive; // Error, intersection with generic type parameter + ~~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r12} = num; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r13} = str; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r14} = u; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r15} = n; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r16} = a; // OK + + var {...r17} = literal_string; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r18} = literal_number; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r19} = e; // Error, enum + ~~~ +!!! error TS2700: Rest types may only be created from object types. + } \ No newline at end of file diff --git a/tests/baselines/reference/restInvalidArgumentType.js b/tests/baselines/reference/restInvalidArgumentType.js new file mode 100644 index 0000000000000..23b46a2f7756f --- /dev/null +++ b/tests/baselines/reference/restInvalidArgumentType.js @@ -0,0 +1,115 @@ +//// [restInvalidArgumentType.ts] +enum E { v1, v2 }; + +function f(p1: T, p2: T[]) { + var t: T; + + var i: T["b"]; + var k: keyof T; + + var mapped_generic: {[P in keyof T]: T[P]}; + var mapped: {[P in "b"]: T[P]}; + + var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; + + var intersection_generic: T & { a: number }; + var intersection_premitive: { a: number } | string; + + var num: number; + var str: number; + + var u: undefined; + var n: null; + + var a: any; + + var literal_string: "string"; + var literal_number: 42; + + var e: E; + + var {...r1} = p1; // Error, generic type paramterre + var {...r2} = p2; // OK + var {...r3} = t; // Error, generic type paramter + + var {...r4} = i; // Error, index access + var {...r5} = k; // Error, index + + var {...r6} = mapped_generic; // Error, generic mapped object type + var {...r7} = mapped; // OK, non-generic mapped type + + var {...r8} = union_generic; // Error, union with generic type parameter + var {...r9} = union_primitive; // Error, union with generic type parameter + + var {...r10} = intersection_generic; // Error, intersection with generic type parameter + var {...r11} = intersection_premitive; // Error, intersection with generic type parameter + + var {...r12} = num; // Error + var {...r13} = str; // Error + + var {...r14} = u; // Error + var {...r15} = n; // Error + + var {...r16} = a; // OK + + var {...r17} = literal_string; // Error + var {...r18} = literal_number; // Error + + var {...r19} = e; // Error, enum +} + +//// [restInvalidArgumentType.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +var E; +(function (E) { + E[E["v1"] = 0] = "v1"; + E[E["v2"] = 1] = "v2"; +})(E || (E = {})); +; +function f(p1, p2) { + var t; + var i; + var k; + var mapped_generic; + var mapped; + var union_generic; + var union_primitive; + var intersection_generic; + var intersection_premitive; + var num; + var str; + var u; + var n; + var a; + var literal_string; + var literal_number; + var e; + var r1 = __rest(p1, []); // Error, generic type paramterre + var r2 = __rest(p2, []); // OK + var r3 = __rest(t, []); // Error, generic type paramter + var r4 = __rest(i, []); // Error, index access + var r5 = __rest(k, []); // Error, index + var r6 = __rest(mapped_generic, []); // Error, generic mapped object type + var r7 = __rest(mapped, []); // OK, non-generic mapped type + var r8 = __rest(union_generic, []); // Error, union with generic type parameter + var r9 = __rest(union_primitive, []); // Error, union with generic type parameter + var r10 = __rest(intersection_generic, []); // Error, intersection with generic type parameter + var r11 = __rest(intersection_premitive, []); // Error, intersection with generic type parameter + var r12 = __rest(num, []); // Error + var r13 = __rest(str, []); // Error + var r14 = __rest(u, []); // Error + var r15 = __rest(n, []); // Error + var r16 = __rest(a, []); // OK + var r17 = __rest(literal_string, []); // Error + var r18 = __rest(literal_number, []); // Error + var r19 = __rest(e, []); // Error, enum +} diff --git a/tests/baselines/reference/spreadIntersection.js b/tests/baselines/reference/spreadIntersection.js new file mode 100644 index 0000000000000..b3fa9f0c2fbc1 --- /dev/null +++ b/tests/baselines/reference/spreadIntersection.js @@ -0,0 +1,23 @@ +//// [spreadIntersection.ts] +var intersection: { a: number } & { b: string }; + +var o1: { a: number, b: string }; +var o1 = { ...intersection }; + +var o2: { a: number, b: string, c: boolean }; +var o2 = { ...intersection, c: false }; + +//// [spreadIntersection.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; +}; +var intersection; +var o1; +var o1 = __assign({}, intersection); +var o2; +var o2 = __assign({}, intersection, { c: false }); diff --git a/tests/baselines/reference/spreadIntersection.symbols b/tests/baselines/reference/spreadIntersection.symbols new file mode 100644 index 0000000000000..1f6b3c12de16c --- /dev/null +++ b/tests/baselines/reference/spreadIntersection.symbols @@ -0,0 +1,26 @@ +=== tests/cases/compiler/spreadIntersection.ts === +var intersection: { a: number } & { b: string }; +>intersection : Symbol(intersection, Decl(spreadIntersection.ts, 0, 3)) +>a : Symbol(a, Decl(spreadIntersection.ts, 0, 19)) +>b : Symbol(b, Decl(spreadIntersection.ts, 0, 35)) + +var o1: { a: number, b: string }; +>o1 : Symbol(o1, Decl(spreadIntersection.ts, 2, 3), Decl(spreadIntersection.ts, 3, 3)) +>a : Symbol(a, Decl(spreadIntersection.ts, 2, 9)) +>b : Symbol(b, Decl(spreadIntersection.ts, 2, 20)) + +var o1 = { ...intersection }; +>o1 : Symbol(o1, Decl(spreadIntersection.ts, 2, 3), Decl(spreadIntersection.ts, 3, 3)) +>intersection : Symbol(intersection, Decl(spreadIntersection.ts, 0, 3)) + +var o2: { a: number, b: string, c: boolean }; +>o2 : Symbol(o2, Decl(spreadIntersection.ts, 5, 3), Decl(spreadIntersection.ts, 6, 3)) +>a : Symbol(a, Decl(spreadIntersection.ts, 5, 9)) +>b : Symbol(b, Decl(spreadIntersection.ts, 5, 20)) +>c : Symbol(c, Decl(spreadIntersection.ts, 5, 31)) + +var o2 = { ...intersection, c: false }; +>o2 : Symbol(o2, Decl(spreadIntersection.ts, 5, 3), Decl(spreadIntersection.ts, 6, 3)) +>intersection : Symbol(intersection, Decl(spreadIntersection.ts, 0, 3)) +>c : Symbol(c, Decl(spreadIntersection.ts, 6, 27)) + diff --git a/tests/baselines/reference/spreadIntersection.types b/tests/baselines/reference/spreadIntersection.types new file mode 100644 index 0000000000000..c3c6b99adeede --- /dev/null +++ b/tests/baselines/reference/spreadIntersection.types @@ -0,0 +1,29 @@ +=== tests/cases/compiler/spreadIntersection.ts === +var intersection: { a: number } & { b: string }; +>intersection : { a: number; } & { b: string; } +>a : number +>b : string + +var o1: { a: number, b: string }; +>o1 : { a: number; b: string; } +>a : number +>b : string + +var o1 = { ...intersection }; +>o1 : { a: number; b: string; } +>{ ...intersection } : { a: number; b: string; } +>intersection : { a: number; } & { b: string; } + +var o2: { a: number, b: string, c: boolean }; +>o2 : { a: number; b: string; c: boolean; } +>a : number +>b : string +>c : boolean + +var o2 = { ...intersection, c: false }; +>o2 : { a: number; b: string; c: boolean; } +>{ ...intersection, c: false } : { c: boolean; a: number; b: string; } +>intersection : { a: number; } & { b: string; } +>c : boolean +>false : false + diff --git a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt new file mode 100644 index 0000000000000..34356e538131f --- /dev/null +++ b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt @@ -0,0 +1,110 @@ +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(50,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(51,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. +tests/cases/compiler/spreadInvalidArgumentType.ts(56,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(58,17): error TS2698: Spread types may only be created from object types. + + +==== tests/cases/compiler/spreadInvalidArgumentType.ts (16 errors) ==== + enum E { v1, v2 }; + + function f(p1: T, p2: T[]) { + var t: T; + + var i: T["b"]; + var k: keyof T; + + var mapped_generic: {[P in keyof T]: T[P]}; + var mapped: {[P in "b"]: T[P]}; + + var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; + + var intersection_generic: T & { a: number }; + var intersection_premitive: { a: number } | string; + + var num: number; + var str: number; + + var u: undefined; + var n: null; + + var a: any; + + var literal_string: "string"; + var literal_number: 42; + + var e: E; + + var o1 = { ...p1 }; // Error, generic type paramterre + ~~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o2 = { ...p2 }; // OK + var o3 = { ...t }; // Error, generic type paramter + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o4 = { ...i }; // Error, index access + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + 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 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 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 o12 = { ...num }; // Error + ~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o13 = { ...str }; // Error + ~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o14 = { ...u }; // Error + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o15 = { ...n }; // Error + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o16 = { ...a }; // OK + + var o17 = { ...literal_string }; // Error + ~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o18 = { ...literal_number }; // Error + ~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o19 = { ...e }; // Error, enum + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + } \ No newline at end of file diff --git a/tests/baselines/reference/spreadInvalidArgumentType.js b/tests/baselines/reference/spreadInvalidArgumentType.js new file mode 100644 index 0000000000000..ecea599842e9a --- /dev/null +++ b/tests/baselines/reference/spreadInvalidArgumentType.js @@ -0,0 +1,114 @@ +//// [spreadInvalidArgumentType.ts] +enum E { v1, v2 }; + +function f(p1: T, p2: T[]) { + var t: T; + + var i: T["b"]; + var k: keyof T; + + var mapped_generic: {[P in keyof T]: T[P]}; + var mapped: {[P in "b"]: T[P]}; + + var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; + + var intersection_generic: T & { a: number }; + var intersection_premitive: { a: number } | string; + + var num: number; + var str: number; + + var u: undefined; + var n: null; + + var a: any; + + var literal_string: "string"; + var literal_number: 42; + + var e: E; + + var o1 = { ...p1 }; // Error, generic type paramterre + var o2 = { ...p2 }; // OK + var o3 = { ...t }; // Error, generic type paramter + + var o4 = { ...i }; // Error, index access + var o5 = { ...k }; // Error, index + + var o6 = { ...mapped_generic }; // Error, 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 o10 = { ...intersection_generic }; // Error, intersection with generic type parameter + var o11 = { ...intersection_premitive }; // Error, intersection with generic type parameter + + var o12 = { ...num }; // Error + var o13 = { ...str }; // Error + + var o14 = { ...u }; // Error + var o15 = { ...n }; // Error + + var o16 = { ...a }; // OK + + var o17 = { ...literal_string }; // Error + var o18 = { ...literal_number }; // Error + + var o19 = { ...e }; // Error, enum +} + +//// [spreadInvalidArgumentType.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; +}; +var E; +(function (E) { + E[E["v1"] = 0] = "v1"; + E[E["v2"] = 1] = "v2"; +})(E || (E = {})); +; +function f(p1, p2) { + var t; + var i; + var k; + var mapped_generic; + var mapped; + var union_generic; + var union_primitive; + var intersection_generic; + var intersection_premitive; + var num; + var str; + var u; + var n; + var a; + var literal_string; + var literal_number; + var e; + var o1 = __assign({}, p1); // Error, generic type paramterre + var o2 = __assign({}, p2); // OK + var o3 = __assign({}, t); // Error, generic type paramter + var o4 = __assign({}, i); // Error, index access + var o5 = __assign({}, k); // Error, index + var o6 = __assign({}, mapped_generic); // Error, 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 o12 = __assign({}, num); // Error + var o13 = __assign({}, str); // Error + var o14 = __assign({}, u); // Error + var o15 = __assign({}, n); // Error + var o16 = __assign({}, a); // OK + var o17 = __assign({}, literal_string); // Error + var o18 = __assign({}, literal_number); // Error + var o19 = __assign({}, e); // Error, enum +} diff --git a/tests/baselines/reference/spreadUnion.js b/tests/baselines/reference/spreadUnion.js new file mode 100644 index 0000000000000..2691a3acdcc22 --- /dev/null +++ b/tests/baselines/reference/spreadUnion.js @@ -0,0 +1,28 @@ +//// [spreadUnion.ts] +var union: { a: number } | { b: string }; + +var o3: { a: number } | { b: string }; +var o3 = { ...union }; + +var o4: { a: boolean } | { b: string , a: boolean}; +var o4 = { ...union, a: false }; + +var o5: { a: number } | { b: string } | { a: number, b: string }; +var o5 = { ...union, ...union }; + +//// [spreadUnion.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; +}; +var union; +var o3; +var o3 = __assign({}, union); +var o4; +var o4 = __assign({}, union, { a: false }); +var o5; +var o5 = __assign({}, union, union); diff --git a/tests/baselines/reference/spreadUnion.symbols b/tests/baselines/reference/spreadUnion.symbols new file mode 100644 index 0000000000000..40a63d56d49c8 --- /dev/null +++ b/tests/baselines/reference/spreadUnion.symbols @@ -0,0 +1,38 @@ +=== tests/cases/compiler/spreadUnion.ts === +var union: { a: number } | { b: string }; +>union : Symbol(union, Decl(spreadUnion.ts, 0, 3)) +>a : Symbol(a, Decl(spreadUnion.ts, 0, 12)) +>b : Symbol(b, Decl(spreadUnion.ts, 0, 28)) + +var o3: { a: number } | { b: string }; +>o3 : Symbol(o3, Decl(spreadUnion.ts, 2, 3), Decl(spreadUnion.ts, 3, 3)) +>a : Symbol(a, Decl(spreadUnion.ts, 2, 9)) +>b : Symbol(b, Decl(spreadUnion.ts, 2, 25)) + +var o3 = { ...union }; +>o3 : Symbol(o3, Decl(spreadUnion.ts, 2, 3), Decl(spreadUnion.ts, 3, 3)) +>union : Symbol(union, Decl(spreadUnion.ts, 0, 3)) + +var o4: { a: boolean } | { b: string , a: boolean}; +>o4 : Symbol(o4, Decl(spreadUnion.ts, 5, 3), Decl(spreadUnion.ts, 6, 3)) +>a : Symbol(a, Decl(spreadUnion.ts, 5, 9)) +>b : Symbol(b, Decl(spreadUnion.ts, 5, 26)) +>a : Symbol(a, Decl(spreadUnion.ts, 5, 38)) + +var o4 = { ...union, a: false }; +>o4 : Symbol(o4, Decl(spreadUnion.ts, 5, 3), Decl(spreadUnion.ts, 6, 3)) +>union : Symbol(union, Decl(spreadUnion.ts, 0, 3)) +>a : Symbol(a, Decl(spreadUnion.ts, 6, 21)) + +var o5: { a: number } | { b: string } | { a: number, b: string }; +>o5 : Symbol(o5, Decl(spreadUnion.ts, 8, 3), Decl(spreadUnion.ts, 9, 3)) +>a : Symbol(a, Decl(spreadUnion.ts, 8, 9)) +>b : Symbol(b, Decl(spreadUnion.ts, 8, 25)) +>a : Symbol(a, Decl(spreadUnion.ts, 8, 41)) +>b : Symbol(b, Decl(spreadUnion.ts, 8, 52)) + +var o5 = { ...union, ...union }; +>o5 : Symbol(o5, Decl(spreadUnion.ts, 8, 3), Decl(spreadUnion.ts, 9, 3)) +>union : Symbol(union, Decl(spreadUnion.ts, 0, 3)) +>union : Symbol(union, Decl(spreadUnion.ts, 0, 3)) + diff --git a/tests/baselines/reference/spreadUnion.types b/tests/baselines/reference/spreadUnion.types new file mode 100644 index 0000000000000..9e5ac1cffd555 --- /dev/null +++ b/tests/baselines/reference/spreadUnion.types @@ -0,0 +1,42 @@ +=== tests/cases/compiler/spreadUnion.ts === +var union: { a: number } | { b: string }; +>union : { a: number; } | { b: string; } +>a : number +>b : string + +var o3: { a: number } | { b: string }; +>o3 : { a: number; } | { b: string; } +>a : number +>b : string + +var o3 = { ...union }; +>o3 : { a: number; } | { b: string; } +>{ ...union } : { a: number; } | { b: string; } +>union : { a: number; } | { b: string; } + +var o4: { a: boolean } | { b: string , a: boolean}; +>o4 : { a: boolean; } | { b: string; a: boolean; } +>a : boolean +>b : string +>a : boolean + +var o4 = { ...union, a: false }; +>o4 : { a: boolean; } | { b: string; a: boolean; } +>{ ...union, a: false } : { a: boolean; } | { a: boolean; b: string; } +>union : { a: number; } | { b: string; } +>a : boolean +>false : false + +var o5: { a: number } | { b: string } | { a: number, b: string }; +>o5 : { a: number; } | { b: string; } | { a: number; b: string; } +>a : number +>b : string +>a : number +>b : string + +var o5 = { ...union, ...union }; +>o5 : { a: number; } | { b: string; } | { a: number; b: string; } +>{ ...union, ...union } : { a: number; } | { b: string; a: number; } | { a: number; b: string; } | { b: string; } +>union : { a: number; } | { b: string; } +>union : { a: number; } | { b: string; } + diff --git a/tests/cases/compiler/restIntersectionOrIntersection.ts b/tests/cases/compiler/restIntersectionOrIntersection.ts new file mode 100644 index 0000000000000..6d06ed5ebc263 --- /dev/null +++ b/tests/cases/compiler/restIntersectionOrIntersection.ts @@ -0,0 +1,10 @@ +var intersection: { x: number, y: number } & { w: string, z: string }; +var union: { a: number, c: boolean } | { a: string, b: string }; + + +var rest1: { y: number, w: string, z: string }; +var {x, ...rest1 } = intersection; + +var rest2: { c: boolean } | { b: string }; +var {a, ...rest2 } = union; + diff --git a/tests/cases/compiler/restInvalidArgumentType.ts b/tests/cases/compiler/restInvalidArgumentType.ts new file mode 100644 index 0000000000000..7f7037bbb333d --- /dev/null +++ b/tests/cases/compiler/restInvalidArgumentType.ts @@ -0,0 +1,59 @@ +enum E { v1, v2 }; + +function f(p1: T, p2: T[]) { + var t: T; + + var i: T["b"]; + var k: keyof T; + + var mapped_generic: {[P in keyof T]: T[P]}; + var mapped: {[P in "b"]: T[P]}; + + var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; + + var intersection_generic: T & { a: number }; + var intersection_premitive: { a: number } | string; + + var num: number; + var str: number; + + var u: undefined; + var n: null; + + var a: any; + + var literal_string: "string"; + var literal_number: 42; + + var e: E; + + var {...r1} = p1; // Error, generic type paramterre + var {...r2} = p2; // OK + var {...r3} = t; // Error, generic type paramter + + var {...r4} = i; // Error, index access + var {...r5} = k; // Error, index + + var {...r6} = mapped_generic; // Error, generic mapped object type + var {...r7} = mapped; // OK, non-generic mapped type + + var {...r8} = union_generic; // Error, union with generic type parameter + var {...r9} = union_primitive; // Error, union with generic type parameter + + var {...r10} = intersection_generic; // Error, intersection with generic type parameter + var {...r11} = intersection_premitive; // Error, intersection with generic type parameter + + var {...r12} = num; // Error + var {...r13} = str; // Error + + var {...r14} = u; // Error + var {...r15} = n; // Error + + var {...r16} = a; // OK + + var {...r17} = literal_string; // Error + var {...r18} = literal_number; // Error + + var {...r19} = e; // Error, enum +} \ No newline at end of file diff --git a/tests/cases/compiler/spreadIntersection.ts b/tests/cases/compiler/spreadIntersection.ts new file mode 100644 index 0000000000000..3b397dc40cc0d --- /dev/null +++ b/tests/cases/compiler/spreadIntersection.ts @@ -0,0 +1,7 @@ +var intersection: { a: number } & { b: string }; + +var o1: { a: number, b: string }; +var o1 = { ...intersection }; + +var o2: { a: number, b: string, c: boolean }; +var o2 = { ...intersection, c: false }; \ No newline at end of file diff --git a/tests/cases/compiler/spreadInvalidArgumentType.ts b/tests/cases/compiler/spreadInvalidArgumentType.ts new file mode 100644 index 0000000000000..bb8f4894711f9 --- /dev/null +++ b/tests/cases/compiler/spreadInvalidArgumentType.ts @@ -0,0 +1,59 @@ +enum E { v1, v2 }; + +function f(p1: T, p2: T[]) { + var t: T; + + var i: T["b"]; + var k: keyof T; + + var mapped_generic: {[P in keyof T]: T[P]}; + var mapped: {[P in "b"]: T[P]}; + + var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; + + var intersection_generic: T & { a: number }; + var intersection_premitive: { a: number } | string; + + var num: number; + var str: number; + + var u: undefined; + var n: null; + + var a: any; + + var literal_string: "string"; + var literal_number: 42; + + var e: E; + + var o1 = { ...p1 }; // Error, generic type paramterre + var o2 = { ...p2 }; // OK + var o3 = { ...t }; // Error, generic type paramter + + var o4 = { ...i }; // Error, index access + var o5 = { ...k }; // Error, index + + var o6 = { ...mapped_generic }; // Error, 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 o10 = { ...intersection_generic }; // Error, intersection with generic type parameter + var o11 = { ...intersection_premitive }; // Error, intersection with generic type parameter + + var o12 = { ...num }; // Error + var o13 = { ...str }; // Error + + var o14 = { ...u }; // Error + var o15 = { ...n }; // Error + + var o16 = { ...a }; // OK + + var o17 = { ...literal_string }; // Error + var o18 = { ...literal_number }; // Error + + var o19 = { ...e }; // Error, enum +} \ No newline at end of file diff --git a/tests/cases/compiler/spreadUnion.ts b/tests/cases/compiler/spreadUnion.ts new file mode 100644 index 0000000000000..ef8440122ed2b --- /dev/null +++ b/tests/cases/compiler/spreadUnion.ts @@ -0,0 +1,10 @@ +var union: { a: number } | { b: string }; + +var o3: { a: number } | { b: string }; +var o3 = { ...union }; + +var o4: { a: boolean } | { b: string , a: boolean}; +var o4 = { ...union, a: false }; + +var o5: { a: number } | { b: string } | { a: number, b: string }; +var o5 = { ...union, ...union }; \ No newline at end of file From 5c10764d9bafbc8fc056b380c597d00ced22e8b9 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 00:13:04 -0800 Subject: [PATCH 03/26] Fix function name --- src/compiler/checker.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e937f6d9b973d..5b3f789732b85 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3098,7 +3098,7 @@ namespace ts { let type: Type; if (pattern.kind === SyntaxKind.ObjectBindingPattern) { if (declaration.dotDotDotToken) { - if (isInvalidValidSpreadType(parentType)) { + if (isInvalidSpreadType(parentType)) { error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); return unknownType; } @@ -11449,7 +11449,7 @@ namespace ts { typeFlags = 0; } const type = checkExpression((memberDecl as SpreadAssignment).expression); - if (!(type.flags & TypeFlags.Any) && isInvalidValidSpreadType(type)) { + if (!(type.flags & TypeFlags.Any) && isInvalidSpreadType(type)) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } @@ -11527,12 +11527,12 @@ namespace ts { } } - function isInvalidValidSpreadType(type: Type): boolean { + function isInvalidSpreadType(type: Type): boolean { if (type.flags & TypeFlags.Object) { return isGenericMappedType(type); } else if (type.flags & TypeFlags.UnionOrIntersection) { - return forEach((type).types, isInvalidValidSpreadType); + return forEach((type).types, isInvalidSpreadType); } return true; } From 5c4f145d6adb073e9f1dd9aeaaa6ac85da76f09e Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 10:36:55 -0800 Subject: [PATCH 04/26] Change name of the function --- src/compiler/checker.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5b3f789732b85..47ea4442e9e3c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3098,7 +3098,7 @@ namespace ts { let type: Type; if (pattern.kind === SyntaxKind.ObjectBindingPattern) { if (declaration.dotDotDotToken) { - if (isInvalidSpreadType(parentType)) { + if (!isValidSpreadType(parentType)) { error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); return unknownType; } @@ -11449,7 +11449,7 @@ namespace ts { typeFlags = 0; } const type = checkExpression((memberDecl as SpreadAssignment).expression); - if (!(type.flags & TypeFlags.Any) && isInvalidSpreadType(type)) { + if (!isValidSpreadType(type)) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } @@ -11527,14 +11527,21 @@ namespace ts { } } - function isInvalidSpreadType(type: Type): boolean { + function isValidSpreadType(type: Type): boolean { + if (type.flags & TypeFlags.Any) { + return true; + } if (type.flags & TypeFlags.Object) { - return isGenericMappedType(type); + return !isGenericMappedType(type); } else if (type.flags & TypeFlags.UnionOrIntersection) { - return forEach((type).types, isInvalidSpreadType); + for (const t of (type).types) { + if (!isValidSpreadType(t)) { + return false; + } + } } - return true; + return false; } function checkJsxSelfClosingElement(node: JsxSelfClosingElement) { From 216f2861335f303cc2fb1abdf18480426cd114c3 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 12:25:10 -0800 Subject: [PATCH 05/26] Handel null and undefined in object spread and rest --- src/compiler/checker.ts | 30 ++++++- .../reference/objectSpreadNegative.errors.txt | 8 +- .../restInvalidArgumentType.errors.txt | 12 +-- .../reference/restInvalidArgumentType.js | 8 +- tests/baselines/reference/restUnion.js | 36 ++++++++ tests/baselines/reference/restUnion.symbols | 44 ++++++++++ tests/baselines/reference/restUnion.types | 45 ++++++++++ tests/baselines/reference/restUnion2.js | 38 +++++++++ tests/baselines/reference/restUnion2.symbols | 52 ++++++++++++ tests/baselines/reference/restUnion2.types | 55 ++++++++++++ .../spreadInvalidArgumentType.errors.txt | 12 +-- .../reference/spreadInvalidArgumentType.js | 8 +- tests/baselines/reference/spreadUnion2.js | 49 +++++++++++ .../baselines/reference/spreadUnion2.symbols | 74 ++++++++++++++++ tests/baselines/reference/spreadUnion2.types | 84 +++++++++++++++++++ .../cases/compiler/restInvalidArgumentType.ts | 4 +- tests/cases/compiler/restUnion.ts | 14 ++++ tests/cases/compiler/restUnion2.ts | 19 +++++ .../compiler/spreadInvalidArgumentType.ts | 4 +- tests/cases/compiler/spreadUnion2.ts | 25 ++++++ 20 files changed, 580 insertions(+), 41 deletions(-) create mode 100644 tests/baselines/reference/restUnion.js create mode 100644 tests/baselines/reference/restUnion.symbols create mode 100644 tests/baselines/reference/restUnion.types create mode 100644 tests/baselines/reference/restUnion2.js create mode 100644 tests/baselines/reference/restUnion2.symbols create mode 100644 tests/baselines/reference/restUnion2.types create mode 100644 tests/baselines/reference/spreadUnion2.js create mode 100644 tests/baselines/reference/spreadUnion2.symbols create mode 100644 tests/baselines/reference/spreadUnion2.types create mode 100644 tests/cases/compiler/restUnion.ts create mode 100644 tests/cases/compiler/restUnion2.ts create mode 100644 tests/cases/compiler/spreadUnion2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 47ea4442e9e3c..8177939fe61d3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3055,7 +3055,10 @@ namespace ts { function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type { if (source.flags & TypeFlags.Union) { - return getUnionType(map((source).types, t => getRestType(t, properties, symbol))); + const types = filter((source).types, t => !(t.flags & TypeFlags.Nullable)); + if (types.length) { + return getUnionType(map(types, t => getRestType(t, properties, symbol))); + } } const members = createMap(); @@ -6111,11 +6114,29 @@ namespace ts { } if (left.flags & TypeFlags.Union) { - return getUnionType(map((left).types, t => getSpreadType(t, right, isFromObjectLiteral))); + const types = filter((left).types, t => !(t.flags & TypeFlags.Nullable)); + if (types.length) { + return getUnionType(map(types, t => getSpreadType(t, right, isFromObjectLiteral))); + } + else { + left = emptyObjectType + } + } + else if (left.flags & TypeFlags.Nullable) { + left = emptyObjectType; } if (right.flags & TypeFlags.Union) { - return getUnionType(map((right).types, t => getSpreadType(left, t, isFromObjectLiteral))); + const types = filter((right).types, t => !(t.flags & TypeFlags.Nullable)); + if (types.length) { + return getUnionType(map(types, t => getSpreadType(left, t, isFromObjectLiteral))); + } + else { + right = emptyObjectType + } + } + else if (right.flags & TypeFlags.Nullable) { + right = emptyObjectType; } const members = createMap(); @@ -11528,7 +11549,7 @@ namespace ts { } function isValidSpreadType(type: Type): boolean { - if (type.flags & TypeFlags.Any) { + if (type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined)) { return true; } if (type.flags & TypeFlags.Object) { @@ -11540,6 +11561,7 @@ namespace ts { return false; } } + return true; } return false; } diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index dc6a356708f12..e92b685b9102e 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -7,8 +7,6 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322 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,20): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,24): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,19): error TS2698: Spread types may only be created from object types. 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(37,20): error TS2698: Spread types may only be created from object types. @@ -20,7 +18,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,14): error TS269 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 (17 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (15 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -68,11 +66,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS269 // null, undefined and primitives are not allowed let spreadNull = { ...null }; - ~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. let spreadUndefind = { ...undefined }; - ~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. let spreadNum = { ...12 }; ~~~~~ !!! error TS2698: Spread types may only be created from object types. diff --git a/tests/baselines/reference/restInvalidArgumentType.errors.txt b/tests/baselines/reference/restInvalidArgumentType.errors.txt index e7cf1ba6f9fc1..fff2c7b3563bc 100644 --- a/tests/baselines/reference/restInvalidArgumentType.errors.txt +++ b/tests/baselines/reference/restInvalidArgumentType.errors.txt @@ -9,14 +9,12 @@ tests/cases/compiler/restInvalidArgumentType.ts(44,13): error TS2700: Rest types tests/cases/compiler/restInvalidArgumentType.ts(45,13): error TS2700: Rest types may only be created from object types. tests/cases/compiler/restInvalidArgumentType.ts(47,13): error TS2700: Rest types may only be created from object types. tests/cases/compiler/restInvalidArgumentType.ts(48,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(50,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(51,13): error TS2700: Rest types may only be created from object types. tests/cases/compiler/restInvalidArgumentType.ts(55,13): error TS2700: Rest types may only be created from object types. tests/cases/compiler/restInvalidArgumentType.ts(56,13): error TS2700: Rest types may only be created from object types. tests/cases/compiler/restInvalidArgumentType.ts(58,13): error TS2700: Rest types may only be created from object types. -==== tests/cases/compiler/restInvalidArgumentType.ts (16 errors) ==== +==== tests/cases/compiler/restInvalidArgumentType.ts (14 errors) ==== enum E { v1, v2 }; function f(p1: T, p2: T[]) { @@ -88,12 +86,8 @@ tests/cases/compiler/restInvalidArgumentType.ts(58,13): error TS2700: Rest types ~~~ !!! error TS2700: Rest types may only be created from object types. - var {...r14} = u; // Error - ~~~ -!!! error TS2700: Rest types may only be created from object types. - var {...r15} = n; // Error - ~~~ -!!! error TS2700: Rest types may only be created from object types. + var {...r14} = u; // OK + var {...r15} = n; // OK var {...r16} = a; // OK diff --git a/tests/baselines/reference/restInvalidArgumentType.js b/tests/baselines/reference/restInvalidArgumentType.js index 23b46a2f7756f..22a547880eb09 100644 --- a/tests/baselines/reference/restInvalidArgumentType.js +++ b/tests/baselines/reference/restInvalidArgumentType.js @@ -48,8 +48,8 @@ function f(p1: T, p2: T[]) { var {...r12} = num; // Error var {...r13} = str; // Error - var {...r14} = u; // Error - var {...r15} = n; // Error + var {...r14} = u; // OK + var {...r15} = n; // OK var {...r16} = a; // OK @@ -106,8 +106,8 @@ function f(p1, p2) { var r11 = __rest(intersection_premitive, []); // Error, intersection with generic type parameter var r12 = __rest(num, []); // Error var r13 = __rest(str, []); // Error - var r14 = __rest(u, []); // Error - var r15 = __rest(n, []); // Error + var r14 = __rest(u, []); // OK + var r15 = __rest(n, []); // OK var r16 = __rest(a, []); // OK var r17 = __rest(literal_string, []); // Error var r18 = __rest(literal_number, []); // Error diff --git a/tests/baselines/reference/restUnion.js b/tests/baselines/reference/restUnion.js new file mode 100644 index 0000000000000..beaf514808b1d --- /dev/null +++ b/tests/baselines/reference/restUnion.js @@ -0,0 +1,36 @@ +//// [restUnion.ts] +var union: { a: number, c: boolean } | { a: string, b: string }; + +var rest1: { c: boolean } | { b: string }; +var {a, ...rest1 } = union; + + +var undefinedUnion: { n: number } | undefined; +var rest2: {}; +var {n, ...rest2 } = undefinedUnion; + + +var nullUnion: { n: number } | null; +var rest3: {}; +var {n, ...rest3 } = nullUnion; + + +//// [restUnion.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +var union; +var rest1; +var a = union.a, rest1 = __rest(union, ["a"]); +var undefinedUnion; +var rest2; +var n = undefinedUnion.n, rest2 = __rest(undefinedUnion, ["n"]); +var nullUnion; +var rest3; +var n = nullUnion.n, rest3 = __rest(nullUnion, ["n"]); diff --git a/tests/baselines/reference/restUnion.symbols b/tests/baselines/reference/restUnion.symbols new file mode 100644 index 0000000000000..660c85badb4e7 --- /dev/null +++ b/tests/baselines/reference/restUnion.symbols @@ -0,0 +1,44 @@ +=== tests/cases/compiler/restUnion.ts === +var union: { a: number, c: boolean } | { a: string, b: string }; +>union : Symbol(union, Decl(restUnion.ts, 0, 3)) +>a : Symbol(a, Decl(restUnion.ts, 0, 12)) +>c : Symbol(c, Decl(restUnion.ts, 0, 23)) +>a : Symbol(a, Decl(restUnion.ts, 0, 40)) +>b : Symbol(b, Decl(restUnion.ts, 0, 51)) + +var rest1: { c: boolean } | { b: string }; +>rest1 : Symbol(rest1, Decl(restUnion.ts, 2, 3), Decl(restUnion.ts, 3, 7)) +>c : Symbol(c, Decl(restUnion.ts, 2, 12)) +>b : Symbol(b, Decl(restUnion.ts, 2, 29)) + +var {a, ...rest1 } = union; +>a : Symbol(a, Decl(restUnion.ts, 3, 5)) +>rest1 : Symbol(rest1, Decl(restUnion.ts, 2, 3), Decl(restUnion.ts, 3, 7)) +>union : Symbol(union, Decl(restUnion.ts, 0, 3)) + + +var undefinedUnion: { n: number } | undefined; +>undefinedUnion : Symbol(undefinedUnion, Decl(restUnion.ts, 6, 3)) +>n : Symbol(n, Decl(restUnion.ts, 6, 21)) + +var rest2: {}; +>rest2 : Symbol(rest2, Decl(restUnion.ts, 7, 3), Decl(restUnion.ts, 8, 7)) + +var {n, ...rest2 } = undefinedUnion; +>n : Symbol(n, Decl(restUnion.ts, 8, 5), Decl(restUnion.ts, 13, 5)) +>rest2 : Symbol(rest2, Decl(restUnion.ts, 7, 3), Decl(restUnion.ts, 8, 7)) +>undefinedUnion : Symbol(undefinedUnion, Decl(restUnion.ts, 6, 3)) + + +var nullUnion: { n: number } | null; +>nullUnion : Symbol(nullUnion, Decl(restUnion.ts, 11, 3)) +>n : Symbol(n, Decl(restUnion.ts, 11, 16)) + +var rest3: {}; +>rest3 : Symbol(rest3, Decl(restUnion.ts, 12, 3), Decl(restUnion.ts, 13, 7)) + +var {n, ...rest3 } = nullUnion; +>n : Symbol(n, Decl(restUnion.ts, 8, 5), Decl(restUnion.ts, 13, 5)) +>rest3 : Symbol(rest3, Decl(restUnion.ts, 12, 3), Decl(restUnion.ts, 13, 7)) +>nullUnion : Symbol(nullUnion, Decl(restUnion.ts, 11, 3)) + diff --git a/tests/baselines/reference/restUnion.types b/tests/baselines/reference/restUnion.types new file mode 100644 index 0000000000000..9837466684b26 --- /dev/null +++ b/tests/baselines/reference/restUnion.types @@ -0,0 +1,45 @@ +=== tests/cases/compiler/restUnion.ts === +var union: { a: number, c: boolean } | { a: string, b: string }; +>union : { a: number; c: boolean; } | { a: string; b: string; } +>a : number +>c : boolean +>a : string +>b : string + +var rest1: { c: boolean } | { b: string }; +>rest1 : { c: boolean; } | { b: string; } +>c : boolean +>b : string + +var {a, ...rest1 } = union; +>a : string | number +>rest1 : { c: boolean; } | { b: string; } +>union : { a: number; c: boolean; } | { a: string; b: string; } + + +var undefinedUnion: { n: number } | undefined; +>undefinedUnion : { n: number; } +>n : number + +var rest2: {}; +>rest2 : {} + +var {n, ...rest2 } = undefinedUnion; +>n : number +>rest2 : {} +>undefinedUnion : { n: number; } + + +var nullUnion: { n: number } | null; +>nullUnion : { n: number; } +>n : number +>null : null + +var rest3: {}; +>rest3 : {} + +var {n, ...rest3 } = nullUnion; +>n : number +>rest3 : {} +>nullUnion : { n: number; } + diff --git a/tests/baselines/reference/restUnion2.js b/tests/baselines/reference/restUnion2.js new file mode 100644 index 0000000000000..d746698164596 --- /dev/null +++ b/tests/baselines/reference/restUnion2.js @@ -0,0 +1,38 @@ +//// [restUnion2.ts] + +declare const undefinedUnion: { n: number } | undefined; +var rest2: { n: number }; +var {...rest2 } = undefinedUnion; + + +declare const nullUnion: { n: number } | null; +var rest3: { n: number }; +var {...rest3 } = nullUnion; + + +declare const nullAndUndefinedUnion: null | undefined; +var rest4: { }; +var {...rest4 } = nullAndUndefinedUnion; + +declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; +var rest5: { n: number, s: string }; +var {...rest5 } = unionWithIntersection; + +//// [restUnion2.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +var rest2; +var rest2 = __rest(undefinedUnion, []); +var rest3; +var rest3 = __rest(nullUnion, []); +var rest4; +var rest4 = __rest(nullAndUndefinedUnion, []); +var rest5; +var rest5 = __rest(unionWithIntersection, []); diff --git a/tests/baselines/reference/restUnion2.symbols b/tests/baselines/reference/restUnion2.symbols new file mode 100644 index 0000000000000..20a113a23b498 --- /dev/null +++ b/tests/baselines/reference/restUnion2.symbols @@ -0,0 +1,52 @@ +=== tests/cases/compiler/restUnion2.ts === + +declare const undefinedUnion: { n: number } | undefined; +>undefinedUnion : Symbol(undefinedUnion, Decl(restUnion2.ts, 1, 13)) +>n : Symbol(n, Decl(restUnion2.ts, 1, 31)) + +var rest2: { n: number }; +>rest2 : Symbol(rest2, Decl(restUnion2.ts, 2, 3), Decl(restUnion2.ts, 3, 5)) +>n : Symbol(n, Decl(restUnion2.ts, 2, 12)) + +var {...rest2 } = undefinedUnion; +>rest2 : Symbol(rest2, Decl(restUnion2.ts, 2, 3), Decl(restUnion2.ts, 3, 5)) +>undefinedUnion : Symbol(undefinedUnion, Decl(restUnion2.ts, 1, 13)) + + +declare const nullUnion: { n: number } | null; +>nullUnion : Symbol(nullUnion, Decl(restUnion2.ts, 6, 13)) +>n : Symbol(n, Decl(restUnion2.ts, 6, 26)) + +var rest3: { n: number }; +>rest3 : Symbol(rest3, Decl(restUnion2.ts, 7, 3), Decl(restUnion2.ts, 8, 5)) +>n : Symbol(n, Decl(restUnion2.ts, 7, 12)) + +var {...rest3 } = nullUnion; +>rest3 : Symbol(rest3, Decl(restUnion2.ts, 7, 3), Decl(restUnion2.ts, 8, 5)) +>nullUnion : Symbol(nullUnion, Decl(restUnion2.ts, 6, 13)) + + +declare const nullAndUndefinedUnion: null | undefined; +>nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(restUnion2.ts, 11, 13)) + +var rest4: { }; +>rest4 : Symbol(rest4, Decl(restUnion2.ts, 12, 3), Decl(restUnion2.ts, 13, 5)) + +var {...rest4 } = nullAndUndefinedUnion; +>rest4 : Symbol(rest4, Decl(restUnion2.ts, 12, 3), Decl(restUnion2.ts, 13, 5)) +>nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(restUnion2.ts, 11, 13)) + +declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; +>unionWithIntersection : Symbol(unionWithIntersection, Decl(restUnion2.ts, 15, 13)) +>n : Symbol(n, Decl(restUnion2.ts, 15, 39)) +>s : Symbol(s, Decl(restUnion2.ts, 15, 55)) + +var rest5: { n: number, s: string }; +>rest5 : Symbol(rest5, Decl(restUnion2.ts, 16, 3), Decl(restUnion2.ts, 17, 5)) +>n : Symbol(n, Decl(restUnion2.ts, 16, 12)) +>s : Symbol(s, Decl(restUnion2.ts, 16, 23)) + +var {...rest5 } = unionWithIntersection; +>rest5 : Symbol(rest5, Decl(restUnion2.ts, 16, 3), Decl(restUnion2.ts, 17, 5)) +>unionWithIntersection : Symbol(unionWithIntersection, Decl(restUnion2.ts, 15, 13)) + diff --git a/tests/baselines/reference/restUnion2.types b/tests/baselines/reference/restUnion2.types new file mode 100644 index 0000000000000..81b768777fd17 --- /dev/null +++ b/tests/baselines/reference/restUnion2.types @@ -0,0 +1,55 @@ +=== tests/cases/compiler/restUnion2.ts === + +declare const undefinedUnion: { n: number } | undefined; +>undefinedUnion : { n: number; } | undefined +>n : number + +var rest2: { n: number }; +>rest2 : { n: number; } +>n : number + +var {...rest2 } = undefinedUnion; +>rest2 : { n: number; } +>undefinedUnion : { n: number; } | undefined + + +declare const nullUnion: { n: number } | null; +>nullUnion : { n: number; } | null +>n : number +>null : null + +var rest3: { n: number }; +>rest3 : { n: number; } +>n : number + +var {...rest3 } = nullUnion; +>rest3 : { n: number; } +>nullUnion : { n: number; } | null + + +declare const nullAndUndefinedUnion: null | undefined; +>nullAndUndefinedUnion : null | undefined +>null : null + +var rest4: { }; +>rest4 : {} + +var {...rest4 } = nullAndUndefinedUnion; +>rest4 : {} +>nullAndUndefinedUnion : null | undefined + +declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; +>unionWithIntersection : ({ n: number; } & { s: string; } & undefined) | null +>n : number +>s : string +>null : null + +var rest5: { n: number, s: string }; +>rest5 : { n: number; s: string; } +>n : number +>s : string + +var {...rest5 } = unionWithIntersection; +>rest5 : { n: number; s: string; } +>unionWithIntersection : ({ n: number; } & { s: string; } & undefined) | null + diff --git a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt index 34356e538131f..5088390f9eea9 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt +++ b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt @@ -9,14 +9,12 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(44,17): error TS2698: Spread t 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(50,17): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(51,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. tests/cases/compiler/spreadInvalidArgumentType.ts(56,17): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(58,17): error TS2698: Spread types may only be created from object types. -==== tests/cases/compiler/spreadInvalidArgumentType.ts (16 errors) ==== +==== tests/cases/compiler/spreadInvalidArgumentType.ts (14 errors) ==== enum E { v1, v2 }; function f(p1: T, p2: T[]) { @@ -88,12 +86,8 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(58,17): error TS2698: Spread t ~~~~~~ !!! error TS2698: Spread types may only be created from object types. - var o14 = { ...u }; // Error - ~~~~ -!!! error TS2698: Spread types may only be created from object types. - var o15 = { ...n }; // Error - ~~~~ -!!! error TS2698: Spread types may only be created from object types. + var o14 = { ...u }; // OK + var o15 = { ...n }; // OK var o16 = { ...a }; // OK diff --git a/tests/baselines/reference/spreadInvalidArgumentType.js b/tests/baselines/reference/spreadInvalidArgumentType.js index ecea599842e9a..26f958f224da3 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.js +++ b/tests/baselines/reference/spreadInvalidArgumentType.js @@ -48,8 +48,8 @@ function f(p1: T, p2: T[]) { var o12 = { ...num }; // Error var o13 = { ...str }; // Error - var o14 = { ...u }; // Error - var o15 = { ...n }; // Error + var o14 = { ...u }; // OK + var o15 = { ...n }; // OK var o16 = { ...a }; // OK @@ -105,8 +105,8 @@ function f(p1, p2) { var o11 = __assign({}, intersection_premitive); // Error, intersection with generic type parameter var o12 = __assign({}, num); // Error var o13 = __assign({}, str); // Error - var o14 = __assign({}, u); // Error - var o15 = __assign({}, n); // Error + var o14 = __assign({}, u); // OK + var o15 = __assign({}, n); // OK var o16 = __assign({}, a); // OK var o17 = __assign({}, literal_string); // Error var o18 = __assign({}, literal_number); // Error diff --git a/tests/baselines/reference/spreadUnion2.js b/tests/baselines/reference/spreadUnion2.js new file mode 100644 index 0000000000000..6c7527af9dd26 --- /dev/null +++ b/tests/baselines/reference/spreadUnion2.js @@ -0,0 +1,49 @@ +//// [spreadUnion2.ts] + +declare const undefinedUnion: { a: number } | undefined; +declare const nullUnion: { b: number } | null; +declare const nullAndUndefinedUnion: null | undefined; + +var o1: { a: number }; +var o1 = { ...undefinedUnion }; + +var o2: { b: number }; +var o2 = { ...nullUnion }; + +var o3: { a: number, b: number }; +var o3 = { ...undefinedUnion, ...nullUnion }; +var o3 = { ...nullUnion, ...undefinedUnion }; + +var o4: { a: number }; +var o4 = { ...undefinedUnion, ...undefinedUnion }; + +var o5: { b: number }; +var o5 = { ...nullUnion, ...nullUnion }; + +var o6: { }; +var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; +var o6 = { ...nullAndUndefinedUnion }; + +//// [spreadUnion2.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; +}; +var o1; +var o1 = __assign({}, undefinedUnion); +var o2; +var o2 = __assign({}, nullUnion); +var o3; +var o3 = __assign({}, undefinedUnion, nullUnion); +var o3 = __assign({}, nullUnion, undefinedUnion); +var o4; +var o4 = __assign({}, undefinedUnion, undefinedUnion); +var o5; +var o5 = __assign({}, nullUnion, nullUnion); +var o6; +var o6 = __assign({}, nullAndUndefinedUnion, nullAndUndefinedUnion); +var o6 = __assign({}, nullAndUndefinedUnion); diff --git a/tests/baselines/reference/spreadUnion2.symbols b/tests/baselines/reference/spreadUnion2.symbols new file mode 100644 index 0000000000000..cc2c194f2a65f --- /dev/null +++ b/tests/baselines/reference/spreadUnion2.symbols @@ -0,0 +1,74 @@ +=== tests/cases/compiler/spreadUnion2.ts === + +declare const undefinedUnion: { a: number } | undefined; +>undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 1, 13)) +>a : Symbol(a, Decl(spreadUnion2.ts, 1, 31)) + +declare const nullUnion: { b: number } | null; +>nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 2, 13)) +>b : Symbol(b, Decl(spreadUnion2.ts, 2, 26)) + +declare const nullAndUndefinedUnion: null | undefined; +>nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 3, 13)) + +var o1: { a: number }; +>o1 : Symbol(o1, Decl(spreadUnion2.ts, 5, 3), Decl(spreadUnion2.ts, 6, 3)) +>a : Symbol(a, Decl(spreadUnion2.ts, 5, 9)) + +var o1 = { ...undefinedUnion }; +>o1 : Symbol(o1, Decl(spreadUnion2.ts, 5, 3), Decl(spreadUnion2.ts, 6, 3)) +>undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 1, 13)) + +var o2: { b: number }; +>o2 : Symbol(o2, Decl(spreadUnion2.ts, 8, 3), Decl(spreadUnion2.ts, 9, 3)) +>b : Symbol(b, Decl(spreadUnion2.ts, 8, 9)) + +var o2 = { ...nullUnion }; +>o2 : Symbol(o2, Decl(spreadUnion2.ts, 8, 3), Decl(spreadUnion2.ts, 9, 3)) +>nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 2, 13)) + +var o3: { a: number, b: number }; +>o3 : Symbol(o3, Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3), Decl(spreadUnion2.ts, 13, 3)) +>a : Symbol(a, Decl(spreadUnion2.ts, 11, 9)) +>b : Symbol(b, Decl(spreadUnion2.ts, 11, 20)) + +var o3 = { ...undefinedUnion, ...nullUnion }; +>o3 : Symbol(o3, Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3), Decl(spreadUnion2.ts, 13, 3)) +>undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 1, 13)) +>nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 2, 13)) + +var o3 = { ...nullUnion, ...undefinedUnion }; +>o3 : Symbol(o3, Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3), Decl(spreadUnion2.ts, 13, 3)) +>nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 2, 13)) +>undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 1, 13)) + +var o4: { a: number }; +>o4 : Symbol(o4, Decl(spreadUnion2.ts, 15, 3), Decl(spreadUnion2.ts, 16, 3)) +>a : Symbol(a, Decl(spreadUnion2.ts, 15, 9)) + +var o4 = { ...undefinedUnion, ...undefinedUnion }; +>o4 : Symbol(o4, Decl(spreadUnion2.ts, 15, 3), Decl(spreadUnion2.ts, 16, 3)) +>undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 1, 13)) +>undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 1, 13)) + +var o5: { b: number }; +>o5 : Symbol(o5, Decl(spreadUnion2.ts, 18, 3), Decl(spreadUnion2.ts, 19, 3)) +>b : Symbol(b, Decl(spreadUnion2.ts, 18, 9)) + +var o5 = { ...nullUnion, ...nullUnion }; +>o5 : Symbol(o5, Decl(spreadUnion2.ts, 18, 3), Decl(spreadUnion2.ts, 19, 3)) +>nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 2, 13)) +>nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 2, 13)) + +var o6: { }; +>o6 : Symbol(o6, Decl(spreadUnion2.ts, 21, 3), Decl(spreadUnion2.ts, 22, 3), Decl(spreadUnion2.ts, 23, 3)) + +var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; +>o6 : Symbol(o6, Decl(spreadUnion2.ts, 21, 3), Decl(spreadUnion2.ts, 22, 3), Decl(spreadUnion2.ts, 23, 3)) +>nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 3, 13)) +>nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 3, 13)) + +var o6 = { ...nullAndUndefinedUnion }; +>o6 : Symbol(o6, Decl(spreadUnion2.ts, 21, 3), Decl(spreadUnion2.ts, 22, 3), Decl(spreadUnion2.ts, 23, 3)) +>nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 3, 13)) + diff --git a/tests/baselines/reference/spreadUnion2.types b/tests/baselines/reference/spreadUnion2.types new file mode 100644 index 0000000000000..cf90381ca77f2 --- /dev/null +++ b/tests/baselines/reference/spreadUnion2.types @@ -0,0 +1,84 @@ +=== tests/cases/compiler/spreadUnion2.ts === + +declare const undefinedUnion: { a: number } | undefined; +>undefinedUnion : { a: number; } | undefined +>a : number + +declare const nullUnion: { b: number } | null; +>nullUnion : { b: number; } | null +>b : number +>null : null + +declare const nullAndUndefinedUnion: null | undefined; +>nullAndUndefinedUnion : null | undefined +>null : null + +var o1: { a: number }; +>o1 : { a: number; } +>a : number + +var o1 = { ...undefinedUnion }; +>o1 : { a: number; } +>{ ...undefinedUnion } : { a: number; } +>undefinedUnion : { a: number; } | undefined + +var o2: { b: number }; +>o2 : { b: number; } +>b : number + +var o2 = { ...nullUnion }; +>o2 : { b: number; } +>{ ...nullUnion } : { b: number; } +>nullUnion : { b: number; } | null + +var o3: { a: number, b: number }; +>o3 : { a: number; b: number; } +>a : number +>b : number + +var o3 = { ...undefinedUnion, ...nullUnion }; +>o3 : { a: number; b: number; } +>{ ...undefinedUnion, ...nullUnion } : { b: number; a: number; } +>undefinedUnion : { a: number; } | undefined +>nullUnion : { b: number; } | null + +var o3 = { ...nullUnion, ...undefinedUnion }; +>o3 : { a: number; b: number; } +>{ ...nullUnion, ...undefinedUnion } : { a: number; b: number; } +>nullUnion : { b: number; } | null +>undefinedUnion : { a: number; } | undefined + +var o4: { a: number }; +>o4 : { a: number; } +>a : number + +var o4 = { ...undefinedUnion, ...undefinedUnion }; +>o4 : { a: number; } +>{ ...undefinedUnion, ...undefinedUnion } : { a: number; } +>undefinedUnion : { a: number; } | undefined +>undefinedUnion : { a: number; } | undefined + +var o5: { b: number }; +>o5 : { b: number; } +>b : number + +var o5 = { ...nullUnion, ...nullUnion }; +>o5 : { b: number; } +>{ ...nullUnion, ...nullUnion } : { b: number; } +>nullUnion : { b: number; } | null +>nullUnion : { b: number; } | null + +var o6: { }; +>o6 : {} + +var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; +>o6 : {} +>{ ...nullAndUndefinedUnion, ...nullAndUndefinedUnion } : {} +>nullAndUndefinedUnion : null | undefined +>nullAndUndefinedUnion : null | undefined + +var o6 = { ...nullAndUndefinedUnion }; +>o6 : {} +>{ ...nullAndUndefinedUnion } : {} +>nullAndUndefinedUnion : null | undefined + diff --git a/tests/cases/compiler/restInvalidArgumentType.ts b/tests/cases/compiler/restInvalidArgumentType.ts index 7f7037bbb333d..488f546e2310a 100644 --- a/tests/cases/compiler/restInvalidArgumentType.ts +++ b/tests/cases/compiler/restInvalidArgumentType.ts @@ -47,8 +47,8 @@ function f(p1: T, p2: T[]) { var {...r12} = num; // Error var {...r13} = str; // Error - var {...r14} = u; // Error - var {...r15} = n; // Error + var {...r14} = u; // OK + var {...r15} = n; // OK var {...r16} = a; // OK diff --git a/tests/cases/compiler/restUnion.ts b/tests/cases/compiler/restUnion.ts new file mode 100644 index 0000000000000..c838b37340f8d --- /dev/null +++ b/tests/cases/compiler/restUnion.ts @@ -0,0 +1,14 @@ +var union: { a: number, c: boolean } | { a: string, b: string }; + +var rest1: { c: boolean } | { b: string }; +var {a, ...rest1 } = union; + + +var undefinedUnion: { n: number } | undefined; +var rest2: {}; +var {n, ...rest2 } = undefinedUnion; + + +var nullUnion: { n: number } | null; +var rest3: {}; +var {n, ...rest3 } = nullUnion; diff --git a/tests/cases/compiler/restUnion2.ts b/tests/cases/compiler/restUnion2.ts new file mode 100644 index 0000000000000..83d94e03a7365 --- /dev/null +++ b/tests/cases/compiler/restUnion2.ts @@ -0,0 +1,19 @@ +// @strictNullChecks: true + +declare const undefinedUnion: { n: number } | undefined; +var rest2: { n: number }; +var {...rest2 } = undefinedUnion; + + +declare const nullUnion: { n: number } | null; +var rest3: { n: number }; +var {...rest3 } = nullUnion; + + +declare const nullAndUndefinedUnion: null | undefined; +var rest4: { }; +var {...rest4 } = nullAndUndefinedUnion; + +declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; +var rest5: { n: number, s: string }; +var {...rest5 } = unionWithIntersection; \ No newline at end of file diff --git a/tests/cases/compiler/spreadInvalidArgumentType.ts b/tests/cases/compiler/spreadInvalidArgumentType.ts index bb8f4894711f9..2ac6aa921f48c 100644 --- a/tests/cases/compiler/spreadInvalidArgumentType.ts +++ b/tests/cases/compiler/spreadInvalidArgumentType.ts @@ -47,8 +47,8 @@ function f(p1: T, p2: T[]) { var o12 = { ...num }; // Error var o13 = { ...str }; // Error - var o14 = { ...u }; // Error - var o15 = { ...n }; // Error + var o14 = { ...u }; // OK + var o15 = { ...n }; // OK var o16 = { ...a }; // OK diff --git a/tests/cases/compiler/spreadUnion2.ts b/tests/cases/compiler/spreadUnion2.ts new file mode 100644 index 0000000000000..25dba81c0dfca --- /dev/null +++ b/tests/cases/compiler/spreadUnion2.ts @@ -0,0 +1,25 @@ +// @strictNullChecks: true + +declare const undefinedUnion: { a: number } | undefined; +declare const nullUnion: { b: number } | null; +declare const nullAndUndefinedUnion: null | undefined; + +var o1: { a: number }; +var o1 = { ...undefinedUnion }; + +var o2: { b: number }; +var o2 = { ...nullUnion }; + +var o3: { a: number, b: number }; +var o3 = { ...undefinedUnion, ...nullUnion }; +var o3 = { ...nullUnion, ...undefinedUnion }; + +var o4: { a: number }; +var o4 = { ...undefinedUnion, ...undefinedUnion }; + +var o5: { b: number }; +var o5 = { ...nullUnion, ...nullUnion }; + +var o6: { }; +var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; +var o6 = { ...nullAndUndefinedUnion }; \ No newline at end of file From 86b48e3f89ada9fc29dee0e20c814830683a3bd2 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 12:26:57 -0800 Subject: [PATCH 06/26] Handel null and undefined in `__rest` --- src/compiler/transformers/destructuring.ts | 2 +- tests/baselines/reference/objectRest.js | 2 +- tests/baselines/reference/objectRestAssignment.js | 2 +- tests/baselines/reference/objectRestForOf.js | 2 +- tests/baselines/reference/objectRestNegative.js | 2 +- tests/baselines/reference/objectRestParameter.js | 2 +- tests/baselines/reference/restIntersectionOrIntersection.js | 2 +- tests/baselines/reference/restInvalidArgumentType.js | 2 +- tests/baselines/reference/restUnion.js | 2 +- tests/baselines/reference/restUnion2.js | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 43590791c83c6..8e32259ff0f2d 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -459,7 +459,7 @@ namespace ts { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/objectRest.js b/tests/baselines/reference/objectRest.js index 85d8a6a573e37..e6d45c7a98aaf 100644 --- a/tests/baselines/reference/objectRest.js +++ b/tests/baselines/reference/objectRest.js @@ -43,7 +43,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/objectRestAssignment.js b/tests/baselines/reference/objectRestAssignment.js index 66ee00f669635..cbdff663c2676 100644 --- a/tests/baselines/reference/objectRestAssignment.js +++ b/tests/baselines/reference/objectRestAssignment.js @@ -19,7 +19,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/objectRestForOf.js b/tests/baselines/reference/objectRestForOf.js index b4e33550cb05f..fd81f77512e19 100644 --- a/tests/baselines/reference/objectRestForOf.js +++ b/tests/baselines/reference/objectRestForOf.js @@ -27,7 +27,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/objectRestNegative.js b/tests/baselines/reference/objectRestNegative.js index f8c5b72ada5d0..915e0a0e86732 100644 --- a/tests/baselines/reference/objectRestNegative.js +++ b/tests/baselines/reference/objectRestNegative.js @@ -23,7 +23,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/objectRestParameter.js b/tests/baselines/reference/objectRestParameter.js index 87419bd06e909..14e84eddfce79 100644 --- a/tests/baselines/reference/objectRestParameter.js +++ b/tests/baselines/reference/objectRestParameter.js @@ -22,7 +22,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/restIntersectionOrIntersection.js b/tests/baselines/reference/restIntersectionOrIntersection.js index a60a5acbd9328..0697e579ecd40 100644 --- a/tests/baselines/reference/restIntersectionOrIntersection.js +++ b/tests/baselines/reference/restIntersectionOrIntersection.js @@ -16,7 +16,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/restInvalidArgumentType.js b/tests/baselines/reference/restInvalidArgumentType.js index 22a547880eb09..48e4e11e8051d 100644 --- a/tests/baselines/reference/restInvalidArgumentType.js +++ b/tests/baselines/reference/restInvalidArgumentType.js @@ -64,7 +64,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/restUnion.js b/tests/baselines/reference/restUnion.js index beaf514808b1d..09a6243d2a957 100644 --- a/tests/baselines/reference/restUnion.js +++ b/tests/baselines/reference/restUnion.js @@ -20,7 +20,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/restUnion2.js b/tests/baselines/reference/restUnion2.js index d746698164596..44a0acfbcf825 100644 --- a/tests/baselines/reference/restUnion2.js +++ b/tests/baselines/reference/restUnion2.js @@ -23,7 +23,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; From 9ab55c157666c6c5ad72cc6d81f44e3335461816 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 12:27:56 -0800 Subject: [PATCH 07/26] change test --- tests/cases/compiler/restIntersectionOrIntersection.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/cases/compiler/restIntersectionOrIntersection.ts b/tests/cases/compiler/restIntersectionOrIntersection.ts index 6d06ed5ebc263..5fca2dafc3654 100644 --- a/tests/cases/compiler/restIntersectionOrIntersection.ts +++ b/tests/cases/compiler/restIntersectionOrIntersection.ts @@ -1,10 +1,4 @@ var intersection: { x: number, y: number } & { w: string, z: string }; -var union: { a: number, c: boolean } | { a: string, b: string }; - var rest1: { y: number, w: string, z: string }; var {x, ...rest1 } = intersection; - -var rest2: { c: boolean } | { b: string }; -var {a, ...rest2 } = union; - From e4f0a50a7cf9f212d7102756e336472af89d2fa7 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 12:29:40 -0800 Subject: [PATCH 08/26] Update test name --- ...nOrIntersection.js => restIntersection.js} | 13 +------ .../reference/restIntersection.symbols | 19 ++++++++++ .../reference/restIntersection.types | 19 ++++++++++ .../restIntersectionOrIntersection.symbols | 38 ------------------- .../restIntersectionOrIntersection.types | 38 ------------------- ...nOrIntersection.ts => restIntersection.ts} | 0 6 files changed, 40 insertions(+), 87 deletions(-) rename tests/baselines/reference/{restIntersectionOrIntersection.js => restIntersection.js} (67%) create mode 100644 tests/baselines/reference/restIntersection.symbols create mode 100644 tests/baselines/reference/restIntersection.types delete mode 100644 tests/baselines/reference/restIntersectionOrIntersection.symbols delete mode 100644 tests/baselines/reference/restIntersectionOrIntersection.types rename tests/cases/compiler/{restIntersectionOrIntersection.ts => restIntersection.ts} (100%) diff --git a/tests/baselines/reference/restIntersectionOrIntersection.js b/tests/baselines/reference/restIntersection.js similarity index 67% rename from tests/baselines/reference/restIntersectionOrIntersection.js rename to tests/baselines/reference/restIntersection.js index 0697e579ecd40..d1f9aa3094cc4 100644 --- a/tests/baselines/reference/restIntersectionOrIntersection.js +++ b/tests/baselines/reference/restIntersection.js @@ -1,17 +1,11 @@ -//// [restIntersectionOrIntersection.ts] +//// [restIntersection.ts] var intersection: { x: number, y: number } & { w: string, z: string }; -var union: { a: number, c: boolean } | { a: string, b: string }; - var rest1: { y: number, w: string, z: string }; var {x, ...rest1 } = intersection; - -var rest2: { c: boolean } | { b: string }; -var {a, ...rest2 } = union; - -//// [restIntersectionOrIntersection.js] +//// [restIntersection.js] var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) @@ -22,8 +16,5 @@ var __rest = (this && this.__rest) || function (s, e) { return t; }; var intersection; -var union; var rest1; var x = intersection.x, rest1 = __rest(intersection, ["x"]); -var rest2; -var a = union.a, rest2 = __rest(union, ["a"]); diff --git a/tests/baselines/reference/restIntersection.symbols b/tests/baselines/reference/restIntersection.symbols new file mode 100644 index 0000000000000..75f91d243e24e --- /dev/null +++ b/tests/baselines/reference/restIntersection.symbols @@ -0,0 +1,19 @@ +=== tests/cases/compiler/restIntersection.ts === +var intersection: { x: number, y: number } & { w: string, z: string }; +>intersection : Symbol(intersection, Decl(restIntersection.ts, 0, 3)) +>x : Symbol(x, Decl(restIntersection.ts, 0, 19)) +>y : Symbol(y, Decl(restIntersection.ts, 0, 30)) +>w : Symbol(w, Decl(restIntersection.ts, 0, 46)) +>z : Symbol(z, Decl(restIntersection.ts, 0, 57)) + +var rest1: { y: number, w: string, z: string }; +>rest1 : Symbol(rest1, Decl(restIntersection.ts, 2, 3), Decl(restIntersection.ts, 3, 7)) +>y : Symbol(y, Decl(restIntersection.ts, 2, 12)) +>w : Symbol(w, Decl(restIntersection.ts, 2, 23)) +>z : Symbol(z, Decl(restIntersection.ts, 2, 34)) + +var {x, ...rest1 } = intersection; +>x : Symbol(x, Decl(restIntersection.ts, 3, 5)) +>rest1 : Symbol(rest1, Decl(restIntersection.ts, 2, 3), Decl(restIntersection.ts, 3, 7)) +>intersection : Symbol(intersection, Decl(restIntersection.ts, 0, 3)) + diff --git a/tests/baselines/reference/restIntersection.types b/tests/baselines/reference/restIntersection.types new file mode 100644 index 0000000000000..5779349ba2986 --- /dev/null +++ b/tests/baselines/reference/restIntersection.types @@ -0,0 +1,19 @@ +=== tests/cases/compiler/restIntersection.ts === +var intersection: { x: number, y: number } & { w: string, z: string }; +>intersection : { x: number; y: number; } & { w: string; z: string; } +>x : number +>y : number +>w : string +>z : string + +var rest1: { y: number, w: string, z: string }; +>rest1 : { y: number; w: string; z: string; } +>y : number +>w : string +>z : string + +var {x, ...rest1 } = intersection; +>x : number +>rest1 : { y: number; w: string; z: string; } +>intersection : { x: number; y: number; } & { w: string; z: string; } + diff --git a/tests/baselines/reference/restIntersectionOrIntersection.symbols b/tests/baselines/reference/restIntersectionOrIntersection.symbols deleted file mode 100644 index f2eb4f16014f0..0000000000000 --- a/tests/baselines/reference/restIntersectionOrIntersection.symbols +++ /dev/null @@ -1,38 +0,0 @@ -=== tests/cases/compiler/restIntersectionOrIntersection.ts === -var intersection: { x: number, y: number } & { w: string, z: string }; ->intersection : Symbol(intersection, Decl(restIntersectionOrIntersection.ts, 0, 3)) ->x : Symbol(x, Decl(restIntersectionOrIntersection.ts, 0, 19)) ->y : Symbol(y, Decl(restIntersectionOrIntersection.ts, 0, 30)) ->w : Symbol(w, Decl(restIntersectionOrIntersection.ts, 0, 46)) ->z : Symbol(z, Decl(restIntersectionOrIntersection.ts, 0, 57)) - -var union: { a: number, c: boolean } | { a: string, b: string }; ->union : Symbol(union, Decl(restIntersectionOrIntersection.ts, 1, 3)) ->a : Symbol(a, Decl(restIntersectionOrIntersection.ts, 1, 12)) ->c : Symbol(c, Decl(restIntersectionOrIntersection.ts, 1, 23)) ->a : Symbol(a, Decl(restIntersectionOrIntersection.ts, 1, 40)) ->b : Symbol(b, Decl(restIntersectionOrIntersection.ts, 1, 51)) - - -var rest1: { y: number, w: string, z: string }; ->rest1 : Symbol(rest1, Decl(restIntersectionOrIntersection.ts, 4, 3), Decl(restIntersectionOrIntersection.ts, 5, 7)) ->y : Symbol(y, Decl(restIntersectionOrIntersection.ts, 4, 12)) ->w : Symbol(w, Decl(restIntersectionOrIntersection.ts, 4, 23)) ->z : Symbol(z, Decl(restIntersectionOrIntersection.ts, 4, 34)) - -var {x, ...rest1 } = intersection; ->x : Symbol(x, Decl(restIntersectionOrIntersection.ts, 5, 5)) ->rest1 : Symbol(rest1, Decl(restIntersectionOrIntersection.ts, 4, 3), Decl(restIntersectionOrIntersection.ts, 5, 7)) ->intersection : Symbol(intersection, Decl(restIntersectionOrIntersection.ts, 0, 3)) - -var rest2: { c: boolean } | { b: string }; ->rest2 : Symbol(rest2, Decl(restIntersectionOrIntersection.ts, 7, 3), Decl(restIntersectionOrIntersection.ts, 8, 7)) ->c : Symbol(c, Decl(restIntersectionOrIntersection.ts, 7, 12)) ->b : Symbol(b, Decl(restIntersectionOrIntersection.ts, 7, 29)) - -var {a, ...rest2 } = union; ->a : Symbol(a, Decl(restIntersectionOrIntersection.ts, 8, 5)) ->rest2 : Symbol(rest2, Decl(restIntersectionOrIntersection.ts, 7, 3), Decl(restIntersectionOrIntersection.ts, 8, 7)) ->union : Symbol(union, Decl(restIntersectionOrIntersection.ts, 1, 3)) - - diff --git a/tests/baselines/reference/restIntersectionOrIntersection.types b/tests/baselines/reference/restIntersectionOrIntersection.types deleted file mode 100644 index c87769ff3ccdf..0000000000000 --- a/tests/baselines/reference/restIntersectionOrIntersection.types +++ /dev/null @@ -1,38 +0,0 @@ -=== tests/cases/compiler/restIntersectionOrIntersection.ts === -var intersection: { x: number, y: number } & { w: string, z: string }; ->intersection : { x: number; y: number; } & { w: string; z: string; } ->x : number ->y : number ->w : string ->z : string - -var union: { a: number, c: boolean } | { a: string, b: string }; ->union : { a: number; c: boolean; } | { a: string; b: string; } ->a : number ->c : boolean ->a : string ->b : string - - -var rest1: { y: number, w: string, z: string }; ->rest1 : { y: number; w: string; z: string; } ->y : number ->w : string ->z : string - -var {x, ...rest1 } = intersection; ->x : number ->rest1 : { y: number; w: string; z: string; } ->intersection : { x: number; y: number; } & { w: string; z: string; } - -var rest2: { c: boolean } | { b: string }; ->rest2 : { c: boolean; } | { b: string; } ->c : boolean ->b : string - -var {a, ...rest2 } = union; ->a : string | number ->rest2 : { c: boolean; } | { b: string; } ->union : { a: number; c: boolean; } | { a: string; b: string; } - - diff --git a/tests/cases/compiler/restIntersectionOrIntersection.ts b/tests/cases/compiler/restIntersection.ts similarity index 100% rename from tests/cases/compiler/restIntersectionOrIntersection.ts rename to tests/cases/compiler/restIntersection.ts From 17b6645a7090589c0adc6b84243ee7dc1e39fbb2 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 13:37:02 -0800 Subject: [PATCH 09/26] add missing semicolons --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8177939fe61d3..936afefce9b85 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6119,7 +6119,7 @@ namespace ts { return getUnionType(map(types, t => getSpreadType(t, right, isFromObjectLiteral))); } else { - left = emptyObjectType + left = emptyObjectType; } } else if (left.flags & TypeFlags.Nullable) { @@ -6132,7 +6132,7 @@ namespace ts { return getUnionType(map(types, t => getSpreadType(left, t, isFromObjectLiteral))); } else { - right = emptyObjectType + right = emptyObjectType; } } else if (right.flags & TypeFlags.Nullable) { From 51f5ef67525ae68acdbb55f626f3ff81dff76d7a Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 13:37:21 -0800 Subject: [PATCH 10/26] Update test --- .../reference/objectSpreadNegative.errors.txt | 22 +++++++++---------- .../reference/objectSpreadNegative.js | 8 ++----- .../types/spread/objectSpreadNegative.ts | 4 +--- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index e92b685b9102e..17f07bc06a296 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -7,15 +7,15 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322 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(34,19): error TS2698: Spread types may only be created from object types. -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(37,20): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(39,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(44,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(48,12): error TS2339: Property 'b' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(54,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,14): error TS2698: Spread types may only be created from object types. -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(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(56,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,14): error TS2698: Spread types may only be created from object types. ==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (15 errors) ==== @@ -64,9 +64,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS269 !!! error TS2300: Duplicate identifier 'b'. let duplicatedSpread = { ...o, ...o } - // null, undefined and primitives are not allowed - let spreadNull = { ...null }; - let spreadUndefind = { ...undefined }; + // primitives are not allowed let spreadNum = { ...12 }; ~~~~~ !!! error TS2698: Spread types may only be created from object types. diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index 6287f4559a79b..dff84355370e7 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -29,9 +29,7 @@ spread = b; // error, missing 's' let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } -// null, undefined and primitives are not allowed -let spreadNull = { ...null }; -let spreadUndefind = { ...undefined }; +// primitives are not allowed let spreadNum = { ...12 }; let spreadSum = { ...1 + 1 }; spreadSum.toFixed(); // error, no methods from number @@ -108,9 +106,7 @@ 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, undefined and primitives are not allowed -var spreadNull = __assign({}, null); -var spreadUndefind = __assign({}, undefined); +// primitives are not allowed var spreadNum = __assign({}, 12); var spreadSum = __assign({}, 1 + 1); spreadSum.toFixed(); // error, no methods from number diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index 3cd819d061350..6d1e0dde42900 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -29,9 +29,7 @@ spread = b; // error, missing 's' let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } -// null, undefined and primitives are not allowed -let spreadNull = { ...null }; -let spreadUndefind = { ...undefined }; +// primitives are not allowed let spreadNum = { ...12 }; let spreadSum = { ...1 + 1 }; spreadSum.toFixed(); // error, no methods from number From fe55edc38e69daaca26efd35bdf40bcb8d173bb4 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 29 Nov 2016 13:46:00 -0800 Subject: [PATCH 11/26] Rest in an untyped binding pattern should be any --- src/compiler/checker.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 527735a3b0f4a..65bc52fde1f97 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3099,6 +3099,15 @@ namespace ts { error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); return unknownType; } + const parent = pattern.parent as VariableLikeDeclaration; + if (parent.kind === SyntaxKind.Parameter && + !parent.type && + !parent.initializer && + !getContextuallyTypedParameterType(parent as ParameterDeclaration)) { + // if this type came from examining the structure of the pattern -- + // there was no other information -- then it is not sufficient to determine the rest type, so just return any + return anyType; + } const literalMembers: PropertyName[] = []; for (const element of pattern.elements) { if (!(element as BindingElement).dotDotDotToken) { From f85ca9c395fa3f6e130b945d6f54471a4b8fac00 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 29 Nov 2016 13:50:56 -0800 Subject: [PATCH 12/26] Test that rest of untyped binding pattern is any --- tests/baselines/reference/objectRest.js | 6 ++++++ tests/baselines/reference/objectRest.symbols | 6 ++++++ tests/baselines/reference/objectRest.types | 8 ++++++++ tests/cases/conformance/types/rest/objectRest.ts | 2 ++ 4 files changed, 22 insertions(+) diff --git a/tests/baselines/reference/objectRest.js b/tests/baselines/reference/objectRest.js index 85d8a6a573e37..f1265fd7e9f58 100644 --- a/tests/baselines/reference/objectRest.js +++ b/tests/baselines/reference/objectRest.js @@ -36,6 +36,8 @@ let computed = 'b'; let computed2 = 'a'; var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; ({ [computed]: stillNotGreat, [computed2]: soSo, ...o } = o); + +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber; //// [objectRest.js] @@ -76,4 +78,8 @@ let computed = 'b'; let computed2 = 'a'; var _g = computed, stillNotGreat = o[_g], _h = computed2, soSo = o[_h], o = __rest(o, [typeof _g === "symbol" ? _g : _g + "", typeof _h === "symbol" ? _h : _h + ""]); (_j = computed, stillNotGreat = o[_j], _k = computed2, soSo = o[_k], o = __rest(o, [typeof _j === "symbol" ? _j : _j + "", typeof _k === "symbol" ? _k : _k + ""])); +var noContextualType = (_a) => { + var { aNumber = 12 } = _a, notEmptyObject = __rest(_a, ["aNumber"]); + return aNumber; +}; var _d, _f, _j, _k; diff --git a/tests/baselines/reference/objectRest.symbols b/tests/baselines/reference/objectRest.symbols index 325258aa8cd6c..6b20982f04dc7 100644 --- a/tests/baselines/reference/objectRest.symbols +++ b/tests/baselines/reference/objectRest.symbols @@ -169,3 +169,9 @@ var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; >o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) >o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber; +>noContextualType : Symbol(noContextualType, Decl(objectRest.ts, 38, 3)) +>aNumber : Symbol(aNumber, Decl(objectRest.ts, 38, 25)) +>notEmptyObject : Symbol(notEmptyObject, Decl(objectRest.ts, 38, 39)) +>aNumber : Symbol(aNumber, Decl(objectRest.ts, 38, 25)) + diff --git a/tests/baselines/reference/objectRest.types b/tests/baselines/reference/objectRest.types index 7d8335437472f..386c55ac8185d 100644 --- a/tests/baselines/reference/objectRest.types +++ b/tests/baselines/reference/objectRest.types @@ -195,3 +195,11 @@ var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; >o : { a: number; b: string; } >o : { a: number; b: string; } +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber; +>noContextualType : ({aNumber, ...notEmptyObject}: { aNumber?: number; }) => number +>({ aNumber = 12, ...notEmptyObject }) => aNumber : ({aNumber, ...notEmptyObject}: { aNumber?: number; }) => number +>aNumber : number +>12 : 12 +>notEmptyObject : any +>aNumber : number + diff --git a/tests/cases/conformance/types/rest/objectRest.ts b/tests/cases/conformance/types/rest/objectRest.ts index 3f7be177c7bb1..fe92bb5356693 100644 --- a/tests/cases/conformance/types/rest/objectRest.ts +++ b/tests/cases/conformance/types/rest/objectRest.ts @@ -36,3 +36,5 @@ let computed = 'b'; let computed2 = 'a'; var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; ({ [computed]: stillNotGreat, [computed2]: soSo, ...o } = o); + +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber; From 2178d5526f7b930a47bac4ef1b0f83d4ceb917bf Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 16:30:27 -0800 Subject: [PATCH 13/26] extract filterNullableTypes --- src/compiler/checker.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 936afefce9b85..c0a487ffa0f08 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3055,7 +3055,7 @@ namespace ts { function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type { if (source.flags & TypeFlags.Union) { - const types = filter((source).types, t => !(t.flags & TypeFlags.Nullable)); + const types = filterNulableTypes(source); if (types.length) { return getUnionType(map(types, t => getRestType(t, properties, symbol))); } @@ -6103,6 +6103,10 @@ namespace ts { return symbol ? getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) : undefined; } + function filterNulableTypes(union: UnionType): Type[] { + return filter(union.types, t => !(t.flags & TypeFlags.Nullable)); + } + /** * 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 @@ -6114,7 +6118,7 @@ namespace ts { } if (left.flags & TypeFlags.Union) { - const types = filter((left).types, t => !(t.flags & TypeFlags.Nullable)); + const types = filterNulableTypes(left); if (types.length) { return getUnionType(map(types, t => getSpreadType(t, right, isFromObjectLiteral))); } @@ -6127,7 +6131,7 @@ namespace ts { } if (right.flags & TypeFlags.Union) { - const types = filter((right).types, t => !(t.flags & TypeFlags.Nullable)); + const types = filterNulableTypes(right); if (types.length) { return getUnionType(map(types, t => getSpreadType(left, t, isFromObjectLiteral))); } From 21526833252bf6f9137c73b7bb6b4c3256df6d2f Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 16:55:50 -0800 Subject: [PATCH 14/26] Simplify logic --- src/compiler/checker.ts | 46 ++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c0a487ffa0f08..56112fe7e861d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3054,11 +3054,13 @@ namespace ts { } function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type { + source = filterType(source, t => !(t.flags & TypeFlags.Nullable)); + if (source.flags & TypeFlags.Never) { + return emptyObjectType; + } + if (source.flags & TypeFlags.Union) { - const types = filterNulableTypes(source); - if (types.length) { - return getUnionType(map(types, t => getRestType(t, properties, symbol))); - } + return mapType(source, t => getRestType(t, properties, symbol)); } const members = createMap(); @@ -6103,10 +6105,6 @@ namespace ts { return symbol ? getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) : undefined; } - function filterNulableTypes(union: UnionType): Type[] { - return filter(union.types, t => !(t.flags & TypeFlags.Nullable)); - } - /** * 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 @@ -6116,31 +6114,19 @@ namespace ts { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } - - if (left.flags & TypeFlags.Union) { - const types = filterNulableTypes(left); - if (types.length) { - return getUnionType(map(types, t => getSpreadType(t, right, isFromObjectLiteral))); - } - else { - left = emptyObjectType; - } + left = filterType(left, t => !(t.flags & TypeFlags.Nullable)); + if (left.flags & TypeFlags.Never) { + return right; } - else if (left.flags & TypeFlags.Nullable) { - left = emptyObjectType; + right = filterType(right, t => !(t.flags & TypeFlags.Nullable)); + if (right.flags & TypeFlags.Never) { + return left; } - - if (right.flags & TypeFlags.Union) { - const types = filterNulableTypes(right); - if (types.length) { - return getUnionType(map(types, t => getSpreadType(left, t, isFromObjectLiteral))); - } - else { - right = emptyObjectType; - } + if (left.flags & TypeFlags.Union) { + return mapType(left, t => getSpreadType(t, right, isFromObjectLiteral)); } - else if (right.flags & TypeFlags.Nullable) { - right = emptyObjectType; + if (right.flags & TypeFlags.Union) { + return mapType(right, t => getSpreadType(left, t, isFromObjectLiteral)); } const members = createMap(); From 505c153fed9e45905c8e9d61f7a8d6fae3d11c29 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 16:57:37 -0800 Subject: [PATCH 15/26] Simplify isValidSpreadType --- src/compiler/checker.ts | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 56112fe7e861d..7dc1ea577089d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11539,21 +11539,9 @@ namespace ts { } function isValidSpreadType(type: Type): boolean { - if (type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined)) { - return true; - } - if (type.flags & TypeFlags.Object) { - return !isGenericMappedType(type); - } - else if (type.flags & TypeFlags.UnionOrIntersection) { - for (const t of (type).types) { - if (!isValidSpreadType(t)) { - return false; - } - } - return true; - } - return false; + return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined) || + type.flags & TypeFlags.Object && !isGenericMappedType(type) || + type.flags & TypeFlags.UnionOrIntersection && !forEach((type).types, t => !isValidSpreadType(t))); } function checkJsxSelfClosingElement(node: JsxSelfClosingElement) { From f6f866e88cf557ef748900ebf6e4b8585eea7934 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Tue, 29 Nov 2016 23:30:14 -0800 Subject: [PATCH 16/26] Reset the noEmitForJsFiles option when updating compiler options (#12570) --- .../unittests/tsserverProjectSystem.ts | 59 +++++++++++++++++++ src/server/project.ts | 11 +++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 368d2a660d4e5..3e9fd7a70e4da 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -2728,6 +2728,65 @@ namespace ts.projectSystem { arguments: { projectFileName: projectName } }).response; assert.isTrue(diags.length === 0); + + session.executeCommand({ + type: "request", + command: server.CommandNames.CompilerOptionsForInferredProjects, + seq: 3, + arguments: { options: { module: ModuleKind.CommonJS } } + }); + const diagsAfterUpdate = session.executeCommand({ + type: "request", + command: server.CommandNames.CompilerOptionsDiagnosticsFull, + seq: 4, + arguments: { projectFileName: projectName } + }).response; + assert.isTrue(diagsAfterUpdate.length === 0); + }); + + it("for external project", () => { + const f1 = { + path: "/a/b/f1.js", + content: "function test1() { }" + }; + const host = createServerHost([f1, libFile]); + const session = createSession(host); + const projectService = session.getProjectService(); + const projectFileName = "/a/b/project.csproj"; + const externalFiles = toExternalFiles([f1.path]); + projectService.openExternalProject({ + projectFileName, + rootFiles: externalFiles, + options: {} + }); + + checkNumberOfProjects(projectService, { externalProjects: 1 }); + + const diags = session.executeCommand({ + type: "request", + command: server.CommandNames.CompilerOptionsDiagnosticsFull, + seq: 2, + arguments: { projectFileName } + }).response; + assert.isTrue(diags.length === 0); + + session.executeCommand({ + type: "request", + command: server.CommandNames.OpenExternalProject, + seq: 3, + arguments: { + projectFileName, + rootFiles: externalFiles, + options: { module: ModuleKind.CommonJS } + } + }); + const diagsAfterUpdate = session.executeCommand({ + type: "request", + command: server.CommandNames.CompilerOptionsDiagnosticsFull, + seq: 4, + arguments: { projectFileName } + }).response; + assert.isTrue(diagsAfterUpdate.length === 0); }); }); diff --git a/src/server/project.ts b/src/server/project.ts index c28b29b944b44..049f61269f886 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -248,9 +248,7 @@ namespace ts.server { this.compilerOptions.allowNonTsExtensions = true; } - if (this.projectKind === ProjectKind.Inferred || this.projectKind === ProjectKind.External) { - this.compilerOptions.noEmitForJsFiles = true; - } + this.setInternalCompilerOptionsForEmittingJsFiles(); this.lsHost = new LSHost(this.projectService.host, this, this.projectService.cancellationToken); this.lsHost.setCompilationSettings(this.compilerOptions); @@ -266,6 +264,12 @@ namespace ts.server { this.markAsDirty(); } + private setInternalCompilerOptionsForEmittingJsFiles() { + if (this.projectKind === ProjectKind.Inferred || this.projectKind === ProjectKind.External) { + this.compilerOptions.noEmitForJsFiles = true; + } + } + getProjectErrors() { return this.projectErrors; } @@ -637,6 +641,7 @@ namespace ts.server { this.lastCachedUnresolvedImportsList = undefined; } this.compilerOptions = compilerOptions; + this.setInternalCompilerOptionsForEmittingJsFiles(); this.lsHost.setCompilationSettings(compilerOptions); this.markAsDirty(); From e14412af0e606be6dfcd0a9cdb4b3538317f3828 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 30 Nov 2016 10:23:33 -0800 Subject: [PATCH 17/26] Improve handling of modifiers in mapped type inference --- src/compiler/checker.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dbaf4ed034ea6..367f64a9b90c6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4532,7 +4532,7 @@ namespace ts { const isomorphicProp = isomorphicType && getPropertyOfType(isomorphicType, propName); const isOptional = templateOptional || !!(isomorphicProp && isomorphicProp.flags & SymbolFlags.Optional); const prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName); - prop.type = addOptionality(propType, isOptional); + prop.type = propType; prop.isReadonly = templateReadonly || isomorphicProp && isReadonlySymbol(isomorphicProp); members[propName] = prop; } @@ -4556,7 +4556,7 @@ namespace ts { function getTemplateTypeFromMappedType(type: MappedType) { return type.templateType || (type.templateType = type.declaration.type ? - instantiateType(getTypeFromTypeNode(type.declaration.type), type.mapper || identityMapper) : + instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), !!type.declaration.questionToken), type.mapper || identityMapper) : unknownType); } @@ -6021,7 +6021,7 @@ namespace ts { } const mapper = createUnaryTypeMapper(getTypeParameterFromMappedType(type), indexType); const templateMapper = type.mapper ? combineTypeMappers(type.mapper, mapper) : mapper; - return addOptionality(instantiateType(getTemplateTypeFromMappedType(type), templateMapper), !!type.declaration.questionToken); + return instantiateType(getTemplateTypeFromMappedType(type), templateMapper); } function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) { @@ -8484,16 +8484,18 @@ namespace ts { const typeInferences = createTypeInferencesObject(); const typeInferencesArray = [typeInferences]; const templateType = getTemplateTypeFromMappedType(target); + const readonlyMask = target.declaration.readonlyToken ? false : true; + const optionalMask = target.declaration.questionToken ? 0 : SymbolFlags.Optional; const properties = getPropertiesOfType(source); const members = createSymbolTable(properties); let hasInferredTypes = false; for (const prop of properties) { const inferredPropType = inferTargetType(getTypeOfSymbol(prop)); if (inferredPropType) { - const inferredProp = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | prop.flags & SymbolFlags.Optional, prop.name); + const inferredProp = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | prop.flags & optionalMask, prop.name); inferredProp.declarations = prop.declarations; inferredProp.type = inferredPropType; - inferredProp.isReadonly = isReadonlySymbol(prop); + inferredProp.isReadonly = readonlyMask && isReadonlySymbol(prop); members[prop.name] = inferredProp; hasInferredTypes = true; } @@ -8502,7 +8504,7 @@ namespace ts { if (indexInfo) { const inferredIndexType = inferTargetType(indexInfo.type); if (inferredIndexType) { - indexInfo = createIndexInfo(inferredIndexType, indexInfo.isReadonly); + indexInfo = createIndexInfo(inferredIndexType, readonlyMask && indexInfo.isReadonly); hasInferredTypes = true; } } From 3870351f056ae7fe5258189d62cb6cb8dc2f0485 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 30 Nov 2016 10:24:02 -0800 Subject: [PATCH 18/26] Accept new baselines --- tests/baselines/reference/mappedTypeErrors.errors.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/mappedTypeErrors.errors.txt b/tests/baselines/reference/mappedTypeErrors.errors.txt index b3cba7eb54d6a..945652bf92956 100644 --- a/tests/baselines/reference/mappedTypeErrors.errors.txt +++ b/tests/baselines/reference/mappedTypeErrors.errors.txt @@ -16,9 +16,9 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(38,24): error TS2344: T Type 'T' is not assignable to type '"visible"'. Type 'string | number' is not assignable to type '"visible"'. Type 'string' is not assignable to type '"visible"'. -tests/cases/conformance/types/mapped/mappedTypeErrors.ts(60,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ [P in keyof T]?: T[P]; }'. +tests/cases/conformance/types/mapped/mappedTypeErrors.ts(60,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ [P in keyof T]?: T[P] | undefined; }'. tests/cases/conformance/types/mapped/mappedTypeErrors.ts(61,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]: T[P]; }'. -tests/cases/conformance/types/mapped/mappedTypeErrors.ts(62,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]?: T[P]; }'. +tests/cases/conformance/types/mapped/mappedTypeErrors.ts(62,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]?: T[P] | undefined; }'. tests/cases/conformance/types/mapped/mappedTypeErrors.ts(67,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ [P in keyof T]: T[P][]; }'. @@ -112,13 +112,13 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(67,9): error TS2403: Su var x: { [P in keyof T]: T[P] }; var x: { [P in keyof T]?: T[P] }; // Error ~ -!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ [P in keyof T]?: T[P]; }'. +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ [P in keyof T]?: T[P] | undefined; }'. var x: { readonly [P in keyof T]: T[P] }; // Error ~ !!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]: T[P]; }'. var x: { readonly [P in keyof T]?: T[P] }; // Error ~ -!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]?: T[P]; }'. +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]?: T[P] | undefined; }'. } function f12() { From 2517187c4a5d01198b60d954b6fb6439c4509236 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 30 Nov 2016 10:24:19 -0800 Subject: [PATCH 19/26] Add tests --- .../isomorphicMappedTypeInference.js | 34 ++++++++++ .../isomorphicMappedTypeInference.symbols | 61 ++++++++++++++++++ .../isomorphicMappedTypeInference.types | 64 +++++++++++++++++++ .../mapped/isomorphicMappedTypeInference.ts | 16 +++++ 4 files changed, 175 insertions(+) diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.js b/tests/baselines/reference/isomorphicMappedTypeInference.js index 0fc646043dcb7..87f3e1c40173d 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.js +++ b/tests/baselines/reference/isomorphicMappedTypeInference.js @@ -103,6 +103,21 @@ function f6(s: string) { }); let v = unboxify(b); let x: string | number | boolean = v[s]; +} + +declare function validate(obj: { [P in keyof T]?: T[P] }): T; +declare function clone(obj: { readonly [P in keyof T]: T[P] }): T; +declare function validateAndClone(obj: { readonly [P in keyof T]?: T[P] }): T; + +type Foo = { + a?: number; + readonly b: string; +} + +function f10(foo: Foo) { + let x = validate(foo); // { a: number, readonly b: string } + let y = clone(foo); // { a?: number, b: string } + let z = validateAndClone(foo); // { a: number, b: string } } //// [isomorphicMappedTypeInference.js] @@ -190,6 +205,11 @@ function f6(s) { var v = unboxify(b); var x = v[s]; } +function f10(foo) { + var x = validate(foo); // { a: number, readonly b: string } + var y = clone(foo); // { a?: number, b: string } + var z = validateAndClone(foo); // { a: number, b: string } +} //// [isomorphicMappedTypeInference.d.ts] @@ -220,3 +240,17 @@ declare function makeDictionary(obj: { [x: string]: T; }; declare function f6(s: string): void; +declare function validate(obj: { + [P in keyof T]?: T[P]; +}): T; +declare function clone(obj: { + readonly [P in keyof T]: T[P]; +}): T; +declare function validateAndClone(obj: { + readonly [P in keyof T]?: T[P]; +}): T; +declare type Foo = { + a?: number; + readonly b: string; +}; +declare function f10(foo: Foo): void; diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.symbols b/tests/baselines/reference/isomorphicMappedTypeInference.symbols index 62dcc6316bcf7..3e8a92e769109 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.symbols +++ b/tests/baselines/reference/isomorphicMappedTypeInference.symbols @@ -332,3 +332,64 @@ function f6(s: string) { >v : Symbol(v, Decl(isomorphicMappedTypeInference.ts, 102, 7)) >s : Symbol(s, Decl(isomorphicMappedTypeInference.ts, 96, 12)) } + +declare function validate(obj: { [P in keyof T]?: T[P] }): T; +>validate : Symbol(validate, Decl(isomorphicMappedTypeInference.ts, 104, 1)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 106, 26)) +>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 106, 29)) +>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 106, 37)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 106, 26)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 106, 26)) +>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 106, 37)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 106, 26)) + +declare function clone(obj: { readonly [P in keyof T]: T[P] }): T; +>clone : Symbol(clone, Decl(isomorphicMappedTypeInference.ts, 106, 64)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 107, 23)) +>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 107, 26)) +>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 107, 43)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 107, 23)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 107, 23)) +>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 107, 43)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 107, 23)) + +declare function validateAndClone(obj: { readonly [P in keyof T]?: T[P] }): T; +>validateAndClone : Symbol(validateAndClone, Decl(isomorphicMappedTypeInference.ts, 107, 69)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 108, 34)) +>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 108, 37)) +>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 108, 54)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 108, 34)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 108, 34)) +>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 108, 54)) +>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 108, 34)) + +type Foo = { +>Foo : Symbol(Foo, Decl(isomorphicMappedTypeInference.ts, 108, 81)) + + a?: number; +>a : Symbol(a, Decl(isomorphicMappedTypeInference.ts, 110, 12)) + + readonly b: string; +>b : Symbol(b, Decl(isomorphicMappedTypeInference.ts, 111, 15)) +} + +function f10(foo: Foo) { +>f10 : Symbol(f10, Decl(isomorphicMappedTypeInference.ts, 113, 1)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 115, 13)) +>Foo : Symbol(Foo, Decl(isomorphicMappedTypeInference.ts, 108, 81)) + + let x = validate(foo); // { a: number, readonly b: string } +>x : Symbol(x, Decl(isomorphicMappedTypeInference.ts, 116, 7)) +>validate : Symbol(validate, Decl(isomorphicMappedTypeInference.ts, 104, 1)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 115, 13)) + + let y = clone(foo); // { a?: number, b: string } +>y : Symbol(y, Decl(isomorphicMappedTypeInference.ts, 117, 7)) +>clone : Symbol(clone, Decl(isomorphicMappedTypeInference.ts, 106, 64)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 115, 13)) + + let z = validateAndClone(foo); // { a: number, b: string } +>z : Symbol(z, Decl(isomorphicMappedTypeInference.ts, 118, 7)) +>validateAndClone : Symbol(validateAndClone, Decl(isomorphicMappedTypeInference.ts, 107, 69)) +>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 115, 13)) +} diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.types b/tests/baselines/reference/isomorphicMappedTypeInference.types index 00a80639f732c..eee2d6cbe7d40 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.types +++ b/tests/baselines/reference/isomorphicMappedTypeInference.types @@ -403,3 +403,67 @@ function f6(s: string) { >v : { [x: string]: string | number | boolean; } >s : string } + +declare function validate(obj: { [P in keyof T]?: T[P] }): T; +>validate : (obj: { [P in keyof T]?: T[P] | undefined; }) => T +>T : T +>obj : { [P in keyof T]?: T[P] | undefined; } +>P : P +>T : T +>T : T +>P : P +>T : T + +declare function clone(obj: { readonly [P in keyof T]: T[P] }): T; +>clone : (obj: { readonly [P in keyof T]: T[P]; }) => T +>T : T +>obj : { readonly [P in keyof T]: T[P]; } +>P : P +>T : T +>T : T +>P : P +>T : T + +declare function validateAndClone(obj: { readonly [P in keyof T]?: T[P] }): T; +>validateAndClone : (obj: { readonly [P in keyof T]?: T[P] | undefined; }) => T +>T : T +>obj : { readonly [P in keyof T]?: T[P] | undefined; } +>P : P +>T : T +>T : T +>P : P +>T : T + +type Foo = { +>Foo : Foo + + a?: number; +>a : number | undefined + + readonly b: string; +>b : string +} + +function f10(foo: Foo) { +>f10 : (foo: Foo) => void +>foo : Foo +>Foo : Foo + + let x = validate(foo); // { a: number, readonly b: string } +>x : { a: number; readonly b: string; } +>validate(foo) : { a: number; readonly b: string; } +>validate : (obj: { [P in keyof T]?: T[P] | undefined; }) => T +>foo : Foo + + let y = clone(foo); // { a?: number, b: string } +>y : { a?: number | undefined; b: string; } +>clone(foo) : { a?: number | undefined; b: string; } +>clone : (obj: { readonly [P in keyof T]: T[P]; }) => T +>foo : Foo + + let z = validateAndClone(foo); // { a: number, b: string } +>z : { a: number; b: string; } +>validateAndClone(foo) : { a: number; b: string; } +>validateAndClone : (obj: { readonly [P in keyof T]?: T[P] | undefined; }) => T +>foo : Foo +} diff --git a/tests/cases/conformance/types/mapped/isomorphicMappedTypeInference.ts b/tests/cases/conformance/types/mapped/isomorphicMappedTypeInference.ts index 19a0c4889a50f..4aab2d95ba39b 100644 --- a/tests/cases/conformance/types/mapped/isomorphicMappedTypeInference.ts +++ b/tests/cases/conformance/types/mapped/isomorphicMappedTypeInference.ts @@ -1,3 +1,4 @@ +// @strictNullChecks: true // @noimplicitany: true // @declaration: true @@ -104,4 +105,19 @@ function f6(s: string) { }); let v = unboxify(b); let x: string | number | boolean = v[s]; +} + +declare function validate(obj: { [P in keyof T]?: T[P] }): T; +declare function clone(obj: { readonly [P in keyof T]: T[P] }): T; +declare function validateAndClone(obj: { readonly [P in keyof T]?: T[P] }): T; + +type Foo = { + a?: number; + readonly b: string; +} + +function f10(foo: Foo) { + let x = validate(foo); // { a: number, readonly b: string } + let y = clone(foo); // { a?: number, b: string } + let z = validateAndClone(foo); // { a: number, b: string } } \ No newline at end of file From 99f352f295e678a1bc46af54be0fa75683a2c41c Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 30 Nov 2016 10:44:00 -0800 Subject: [PATCH 20/26] Rest of untyped binding pattern is string-indexed type This is more correct than any and the code is more elegant as well. --- src/compiler/checker.ts | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 65bc52fde1f97..c4920c297703d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3099,15 +3099,6 @@ namespace ts { error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); return unknownType; } - const parent = pattern.parent as VariableLikeDeclaration; - if (parent.kind === SyntaxKind.Parameter && - !parent.type && - !parent.initializer && - !getContextuallyTypedParameterType(parent as ParameterDeclaration)) { - // if this type came from examining the structure of the pattern -- - // there was no other information -- then it is not sufficient to determine the rest type, so just return any - return anyType; - } const literalMembers: PropertyName[] = []; for (const element of pattern.elements) { if (!(element as BindingElement).dotDotDotToken) { @@ -3318,14 +3309,19 @@ namespace ts { // Return the type implied by an object binding pattern function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { const members = createMap(); + let stringIndexInfo: IndexInfo; let hasComputedProperties = false; forEach(pattern.elements, e => { const name = e.propertyName || e.name; - if (isComputedNonLiteralName(name) || e.dotDotDotToken) { - // do not include computed properties or rests in the implied type + if (isComputedNonLiteralName(name)) { + // do not include computed properties in the implied type hasComputedProperties = true; return; } + if (e.dotDotDotToken) { + stringIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false); + return; + } const text = getTextOfPropertyName(name); const flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0); @@ -3334,7 +3330,7 @@ namespace ts { symbol.bindingElement = e; members[symbol.name] = symbol; }); - const result = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined); + const result = createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, undefined); if (includePatternInType) { result.pattern = pattern; } @@ -11422,7 +11418,8 @@ namespace ts { if (impliedProp) { prop.flags |= impliedProp.flags & SymbolFlags.Optional; } - else if (!compilerOptions.suppressExcessPropertyErrors) { + + else if (!compilerOptions.suppressExcessPropertyErrors && !getIndexInfoOfType(contextualType, IndexKind.String)) { error(memberDecl.name, Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, symbolToString(member), typeToString(contextualType)); } From 074ed9f8d6fa937986f3ecf37130dd0eac11a15a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 30 Nov 2016 10:44:56 -0800 Subject: [PATCH 21/26] Update baselines --- tests/baselines/reference/objectRest.types | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/baselines/reference/objectRest.types b/tests/baselines/reference/objectRest.types index 386c55ac8185d..bc1ca95af9a38 100644 --- a/tests/baselines/reference/objectRest.types +++ b/tests/baselines/reference/objectRest.types @@ -196,10 +196,10 @@ var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; >o : { a: number; b: string; } var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber; ->noContextualType : ({aNumber, ...notEmptyObject}: { aNumber?: number; }) => number ->({ aNumber = 12, ...notEmptyObject }) => aNumber : ({aNumber, ...notEmptyObject}: { aNumber?: number; }) => number +>noContextualType : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => number +>({ aNumber = 12, ...notEmptyObject }) => aNumber : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => number >aNumber : number >12 : 12 ->notEmptyObject : any +>notEmptyObject : { [x: string]: any; } >aNumber : number From f6ace2d83df99b016d6aaf986d330f2f23ee6dfa Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 30 Nov 2016 13:14:08 -0800 Subject: [PATCH 22/26] Rest of untyped binding pattern is back to any --- src/compiler/checker.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c4920c297703d..cb8f049f3a9ad 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3106,6 +3106,12 @@ namespace ts { } } type = getRestType(parentType, literalMembers, declaration.symbol); + if (getPropertiesOfObjectType(type).length === 0 && getIndexTypeOfType(type, IndexKind.String) === anyType) { + if (compilerOptions.noImplicitAny) { + reportImplicitAnyError(declaration, anyType); + } + return anyType; + } } else { // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) From 8e648f9f6d7cf7f0b39ab4bd776e5a0dba24cdc3 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 30 Nov 2016 13:14:52 -0800 Subject: [PATCH 23/26] Add property access and --noImplicitAny tests And update baselines --- tests/baselines/reference/objectRest.js | 4 ++-- tests/baselines/reference/objectRest.symbols | 3 ++- tests/baselines/reference/objectRest.types | 12 ++++++++---- .../reference/objectRestNegative.errors.txt | 13 ++++++++++++- tests/baselines/reference/objectRestNegative.js | 6 ++++++ tests/cases/conformance/types/rest/objectRest.ts | 2 +- .../conformance/types/rest/objectRestNegative.ts | 3 +++ 7 files changed, 34 insertions(+), 9 deletions(-) diff --git a/tests/baselines/reference/objectRest.js b/tests/baselines/reference/objectRest.js index f1265fd7e9f58..448b54a8610dc 100644 --- a/tests/baselines/reference/objectRest.js +++ b/tests/baselines/reference/objectRest.js @@ -37,7 +37,7 @@ let computed2 = 'a'; var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; ({ [computed]: stillNotGreat, [computed2]: soSo, ...o } = o); -var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber; +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes; //// [objectRest.js] @@ -80,6 +80,6 @@ var _g = computed, stillNotGreat = o[_g], _h = computed2, soSo = o[_h], o = __re (_j = computed, stillNotGreat = o[_j], _k = computed2, soSo = o[_k], o = __rest(o, [typeof _j === "symbol" ? _j : _j + "", typeof _k === "symbol" ? _k : _k + ""])); var noContextualType = (_a) => { var { aNumber = 12 } = _a, notEmptyObject = __rest(_a, ["aNumber"]); - return aNumber; + return aNumber + notEmptyObject.anythingGoes; }; var _d, _f, _j, _k; diff --git a/tests/baselines/reference/objectRest.symbols b/tests/baselines/reference/objectRest.symbols index 6b20982f04dc7..5bacb33f5dad5 100644 --- a/tests/baselines/reference/objectRest.symbols +++ b/tests/baselines/reference/objectRest.symbols @@ -169,9 +169,10 @@ var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; >o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) >o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) -var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber; +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes; >noContextualType : Symbol(noContextualType, Decl(objectRest.ts, 38, 3)) >aNumber : Symbol(aNumber, Decl(objectRest.ts, 38, 25)) >notEmptyObject : Symbol(notEmptyObject, Decl(objectRest.ts, 38, 39)) >aNumber : Symbol(aNumber, Decl(objectRest.ts, 38, 25)) +>notEmptyObject : Symbol(notEmptyObject, Decl(objectRest.ts, 38, 39)) diff --git a/tests/baselines/reference/objectRest.types b/tests/baselines/reference/objectRest.types index bc1ca95af9a38..4122e4a15358f 100644 --- a/tests/baselines/reference/objectRest.types +++ b/tests/baselines/reference/objectRest.types @@ -195,11 +195,15 @@ var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; >o : { a: number; b: string; } >o : { a: number; b: string; } -var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber; ->noContextualType : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => number ->({ aNumber = 12, ...notEmptyObject }) => aNumber : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => number +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes; +>noContextualType : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => any +>({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => any >aNumber : number >12 : 12 ->notEmptyObject : { [x: string]: any; } +>notEmptyObject : any +>aNumber + notEmptyObject.anythingGoes : any >aNumber : number +>notEmptyObject.anythingGoes : any +>notEmptyObject : any +>anythingGoes : any diff --git a/tests/baselines/reference/objectRestNegative.errors.txt b/tests/baselines/reference/objectRestNegative.errors.txt index 345e99723bd66..325b30b8a7efa 100644 --- a/tests/baselines/reference/objectRestNegative.errors.txt +++ b/tests/baselines/reference/objectRestNegative.errors.txt @@ -3,11 +3,14 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(6,10): error TS2322: Ty Types of property 'a' are incompatible. Type 'number' is not assignable to type 'string'. tests/cases/conformance/types/rest/objectRestNegative.ts(9,31): error TS2462: A rest element must be last in a destructuring pattern +tests/cases/conformance/types/rest/objectRestNegative.ts(11,30): error TS7008: Member 'x' implicitly has an 'any' type. +tests/cases/conformance/types/rest/objectRestNegative.ts(11,33): error TS7008: Member 'y' implicitly has an 'any' type. tests/cases/conformance/types/rest/objectRestNegative.ts(12,17): error TS2700: Rest types may only be created from object types. tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: The target of an object rest assignment must be a variable or a property access. +tests/cases/conformance/types/rest/objectRestNegative.ts(19,44): error TS7031: Binding element 'implicitlyAny' implicitly has an 'any' type. -==== tests/cases/conformance/types/rest/objectRestNegative.ts (5 errors) ==== +==== tests/cases/conformance/types/rest/objectRestNegative.ts (8 errors) ==== let o = { a: 1, b: 'no' }; var { ...mustBeLast, a } = o; ~~~~~~~~~~ @@ -27,6 +30,10 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: Th !!! error TS2462: A rest element must be last in a destructuring pattern } function generic(t: T) { + ~~ +!!! error TS7008: Member 'x' implicitly has an 'any' type. + ~ +!!! error TS7008: Member 'y' implicitly has an 'any' type. let { x, ...rest } = t; ~~~~ !!! error TS2700: Rest types may only be created from object types. @@ -37,4 +44,8 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: Th ({a, ...rest.b + rest.b} = o); ~~~~~~~~~~~~~~~ !!! error TS2701: The target of an object rest assignment must be a variable or a property access. + + var noContextualType = ({ aNumber = 12, ...implicitlyAny }) => aNumber + implicitlyAny.anythingGoes; + ~~~~~~~~~~~~~ +!!! error TS7031: Binding element 'implicitlyAny' implicitly has an 'any' type. \ No newline at end of file diff --git a/tests/baselines/reference/objectRestNegative.js b/tests/baselines/reference/objectRestNegative.js index f8c5b72ada5d0..ece890544c347 100644 --- a/tests/baselines/reference/objectRestNegative.js +++ b/tests/baselines/reference/objectRestNegative.js @@ -16,6 +16,8 @@ function generic(t: T) { let rest: { b: string } ({a, ...rest.b + rest.b} = o); + +var noContextualType = ({ aNumber = 12, ...implicitlyAny }) => aNumber + implicitlyAny.anythingGoes; //// [objectRestNegative.js] @@ -42,3 +44,7 @@ function generic(t) { } var rest; (a = o.a, o, rest.b + rest.b = __rest(o, ["a"])); +var noContextualType = function (_a) { + var _b = _a.aNumber, aNumber = _b === void 0 ? 12 : _b, implicitlyAny = __rest(_a, ["aNumber"]); + return aNumber + implicitlyAny.anythingGoes; +}; diff --git a/tests/cases/conformance/types/rest/objectRest.ts b/tests/cases/conformance/types/rest/objectRest.ts index fe92bb5356693..5891ce2414b21 100644 --- a/tests/cases/conformance/types/rest/objectRest.ts +++ b/tests/cases/conformance/types/rest/objectRest.ts @@ -37,4 +37,4 @@ let computed2 = 'a'; var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; ({ [computed]: stillNotGreat, [computed2]: soSo, ...o } = o); -var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber; +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes; diff --git a/tests/cases/conformance/types/rest/objectRestNegative.ts b/tests/cases/conformance/types/rest/objectRestNegative.ts index c224c8cd30e34..c0477e71db519 100644 --- a/tests/cases/conformance/types/rest/objectRestNegative.ts +++ b/tests/cases/conformance/types/rest/objectRestNegative.ts @@ -1,3 +1,4 @@ +// @noImplicitAny: true let o = { a: 1, b: 'no' }; var { ...mustBeLast, a } = o; @@ -15,3 +16,5 @@ function generic(t: T) { let rest: { b: string } ({a, ...rest.b + rest.b} = o); + +var noContextualType = ({ aNumber = 12, ...implicitlyAny }) => aNumber + implicitlyAny.anythingGoes; From adf9b26f50763ac9989d3a61df56bb74fc9007b1 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 30 Nov 2016 16:28:26 -0800 Subject: [PATCH 24/26] Handle parameter type error for index signature in declaration emit Fixes #12572 --- src/compiler/declarationEmitter.ts | 6 ++++++ src/compiler/diagnosticMessages.json | 8 ++++++++ .../declarationEmitIndexTypeNotFound.errors.txt | 17 +++++++++++++++++ .../declarationEmitIndexTypeNotFound.js | 9 +++++++++ .../declarationEmitIndexTypeNotFound.ts | 5 +++++ 5 files changed, 45 insertions(+) create mode 100644 tests/baselines/reference/declarationEmitIndexTypeNotFound.errors.txt create mode 100644 tests/baselines/reference/declarationEmitIndexTypeNotFound.js create mode 100644 tests/cases/compiler/declarationEmitIndexTypeNotFound.ts diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index fd2740f20c2e6..38e0db0ba6b74 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -1625,6 +1625,12 @@ namespace ts { Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; + case SyntaxKind.IndexSignature: + // Interfaces cannot have parameter types that cannot be named + return symbolAccessibilityResult.errorModuleName ? + Diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : + Diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_private_name_1; + case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: if (hasModifier(node.parent, ModifierFlags.Static)) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 007986e23bee0..5f49c54a2af22 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2300,6 +2300,14 @@ "category": "Message", "code": 4090 }, + "Parameter '{0}' of index signature from exported interface has or is using name '{1}' from private module '{2}'.": { + "category": "Error", + "code": 4091 + }, + "Parameter '{0}' of index signature from exported interface has or is using private name '{1}'.": { + "category": "Error", + "code": 4092 + }, "The current host does not support the '{0}' option.": { "category": "Error", diff --git a/tests/baselines/reference/declarationEmitIndexTypeNotFound.errors.txt b/tests/baselines/reference/declarationEmitIndexTypeNotFound.errors.txt new file mode 100644 index 0000000000000..ffbfd25fa949f --- /dev/null +++ b/tests/baselines/reference/declarationEmitIndexTypeNotFound.errors.txt @@ -0,0 +1,17 @@ +tests/cases/compiler/declarationEmitIndexTypeNotFound.ts(3,6): error TS1023: An index signature parameter type must be 'string' or 'number'. +tests/cases/compiler/declarationEmitIndexTypeNotFound.ts(3,13): error TS2304: Cannot find name 'TypeNotFound'. +tests/cases/compiler/declarationEmitIndexTypeNotFound.ts(3,13): error TS4092: Parameter 'index' of index signature from exported interface has or is using private name 'TypeNotFound'. + + +==== tests/cases/compiler/declarationEmitIndexTypeNotFound.ts (3 errors) ==== + + export interface Test { + [index: TypeNotFound]: any; + ~~~~~ +!!! error TS1023: An index signature parameter type must be 'string' or 'number'. + ~~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'TypeNotFound'. + ~~~~~~~~~~~~ +!!! error TS4092: Parameter 'index' of index signature from exported interface has or is using private name 'TypeNotFound'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/declarationEmitIndexTypeNotFound.js b/tests/baselines/reference/declarationEmitIndexTypeNotFound.js new file mode 100644 index 0000000000000..22100e5cb7229 --- /dev/null +++ b/tests/baselines/reference/declarationEmitIndexTypeNotFound.js @@ -0,0 +1,9 @@ +//// [declarationEmitIndexTypeNotFound.ts] + +export interface Test { + [index: TypeNotFound]: any; +} + + +//// [declarationEmitIndexTypeNotFound.js] +"use strict"; diff --git a/tests/cases/compiler/declarationEmitIndexTypeNotFound.ts b/tests/cases/compiler/declarationEmitIndexTypeNotFound.ts new file mode 100644 index 0000000000000..de3316cd56f9e --- /dev/null +++ b/tests/cases/compiler/declarationEmitIndexTypeNotFound.ts @@ -0,0 +1,5 @@ +// @declaration: true + +export interface Test { + [index: TypeNotFound]: any; +} From ddf03bae3c8cb330b7a485c621d917878aaf36c8 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 30 Nov 2016 17:25:44 -0800 Subject: [PATCH 25/26] Rest of untyped binding pattern is back to str index sig --- src/compiler/checker.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cb8f049f3a9ad..c4920c297703d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3106,12 +3106,6 @@ namespace ts { } } type = getRestType(parentType, literalMembers, declaration.symbol); - if (getPropertiesOfObjectType(type).length === 0 && getIndexTypeOfType(type, IndexKind.String) === anyType) { - if (compilerOptions.noImplicitAny) { - reportImplicitAnyError(declaration, anyType); - } - return anyType; - } } else { // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) From 77226318ef839c16390974a8f20635af512367f2 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 30 Nov 2016 17:26:30 -0800 Subject: [PATCH 26/26] Update baselines --- tests/baselines/reference/objectRest.js | 4 ++-- tests/baselines/reference/objectRest.symbols | 2 +- tests/baselines/reference/objectRest.types | 14 +++++++------- .../reference/objectRestNegative.errors.txt | 8 ++++---- tests/baselines/reference/objectRestNegative.js | 6 +++--- tests/cases/conformance/types/rest/objectRest.ts | 2 +- .../conformance/types/rest/objectRestNegative.ts | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/baselines/reference/objectRest.js b/tests/baselines/reference/objectRest.js index 448b54a8610dc..272a73661ac15 100644 --- a/tests/baselines/reference/objectRest.js +++ b/tests/baselines/reference/objectRest.js @@ -37,7 +37,7 @@ let computed2 = 'a'; var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; ({ [computed]: stillNotGreat, [computed2]: soSo, ...o } = o); -var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes; +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes']; //// [objectRest.js] @@ -80,6 +80,6 @@ var _g = computed, stillNotGreat = o[_g], _h = computed2, soSo = o[_h], o = __re (_j = computed, stillNotGreat = o[_j], _k = computed2, soSo = o[_k], o = __rest(o, [typeof _j === "symbol" ? _j : _j + "", typeof _k === "symbol" ? _k : _k + ""])); var noContextualType = (_a) => { var { aNumber = 12 } = _a, notEmptyObject = __rest(_a, ["aNumber"]); - return aNumber + notEmptyObject.anythingGoes; + return aNumber + notEmptyObject['anythingGoes']; }; var _d, _f, _j, _k; diff --git a/tests/baselines/reference/objectRest.symbols b/tests/baselines/reference/objectRest.symbols index 5bacb33f5dad5..4630939213515 100644 --- a/tests/baselines/reference/objectRest.symbols +++ b/tests/baselines/reference/objectRest.symbols @@ -169,7 +169,7 @@ var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; >o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) >o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) -var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes; +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes']; >noContextualType : Symbol(noContextualType, Decl(objectRest.ts, 38, 3)) >aNumber : Symbol(aNumber, Decl(objectRest.ts, 38, 25)) >notEmptyObject : Symbol(notEmptyObject, Decl(objectRest.ts, 38, 39)) diff --git a/tests/baselines/reference/objectRest.types b/tests/baselines/reference/objectRest.types index 4122e4a15358f..1dc0574171344 100644 --- a/tests/baselines/reference/objectRest.types +++ b/tests/baselines/reference/objectRest.types @@ -195,15 +195,15 @@ var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; >o : { a: number; b: string; } >o : { a: number; b: string; } -var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes; +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes']; >noContextualType : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => any ->({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => any +>({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes'] : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => any >aNumber : number >12 : 12 ->notEmptyObject : any ->aNumber + notEmptyObject.anythingGoes : any +>notEmptyObject : { [x: string]: any; } +>aNumber + notEmptyObject['anythingGoes'] : any >aNumber : number ->notEmptyObject.anythingGoes : any ->notEmptyObject : any ->anythingGoes : any +>notEmptyObject['anythingGoes'] : any +>notEmptyObject : { [x: string]: any; } +>'anythingGoes' : "anythingGoes" diff --git a/tests/baselines/reference/objectRestNegative.errors.txt b/tests/baselines/reference/objectRestNegative.errors.txt index 325b30b8a7efa..6e65af4bdc138 100644 --- a/tests/baselines/reference/objectRestNegative.errors.txt +++ b/tests/baselines/reference/objectRestNegative.errors.txt @@ -7,7 +7,7 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(11,30): error TS7008: M tests/cases/conformance/types/rest/objectRestNegative.ts(11,33): error TS7008: Member 'y' implicitly has an 'any' type. tests/cases/conformance/types/rest/objectRestNegative.ts(12,17): error TS2700: Rest types may only be created from object types. tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: The target of an object rest assignment must be a variable or a property access. -tests/cases/conformance/types/rest/objectRestNegative.ts(19,44): error TS7031: Binding element 'implicitlyAny' implicitly has an 'any' type. +tests/cases/conformance/types/rest/objectRestNegative.ts(19,90): error TS2339: Property 'anythingGoes' does not exist on type '{ [x: string]: any; }'. ==== tests/cases/conformance/types/rest/objectRestNegative.ts (8 errors) ==== @@ -45,7 +45,7 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(19,44): error TS7031: B ~~~~~~~~~~~~~~~ !!! error TS2701: The target of an object rest assignment must be a variable or a property access. - var noContextualType = ({ aNumber = 12, ...implicitlyAny }) => aNumber + implicitlyAny.anythingGoes; - ~~~~~~~~~~~~~ -!!! error TS7031: Binding element 'implicitlyAny' implicitly has an 'any' type. + var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes; + ~~~~~~~~~~~~ +!!! error TS2339: Property 'anythingGoes' does not exist on type '{ [x: string]: any; }'. \ No newline at end of file diff --git a/tests/baselines/reference/objectRestNegative.js b/tests/baselines/reference/objectRestNegative.js index ece890544c347..4a6ea6f72576f 100644 --- a/tests/baselines/reference/objectRestNegative.js +++ b/tests/baselines/reference/objectRestNegative.js @@ -17,7 +17,7 @@ function generic(t: T) { let rest: { b: string } ({a, ...rest.b + rest.b} = o); -var noContextualType = ({ aNumber = 12, ...implicitlyAny }) => aNumber + implicitlyAny.anythingGoes; +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes; //// [objectRestNegative.js] @@ -45,6 +45,6 @@ function generic(t) { var rest; (a = o.a, o, rest.b + rest.b = __rest(o, ["a"])); var noContextualType = function (_a) { - var _b = _a.aNumber, aNumber = _b === void 0 ? 12 : _b, implicitlyAny = __rest(_a, ["aNumber"]); - return aNumber + implicitlyAny.anythingGoes; + var _b = _a.aNumber, aNumber = _b === void 0 ? 12 : _b, notEmptyObject = __rest(_a, ["aNumber"]); + return aNumber + notEmptyObject.anythingGoes; }; diff --git a/tests/cases/conformance/types/rest/objectRest.ts b/tests/cases/conformance/types/rest/objectRest.ts index 5891ce2414b21..2fba5d0b6dcd8 100644 --- a/tests/cases/conformance/types/rest/objectRest.ts +++ b/tests/cases/conformance/types/rest/objectRest.ts @@ -37,4 +37,4 @@ let computed2 = 'a'; var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; ({ [computed]: stillNotGreat, [computed2]: soSo, ...o } = o); -var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes; +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes']; diff --git a/tests/cases/conformance/types/rest/objectRestNegative.ts b/tests/cases/conformance/types/rest/objectRestNegative.ts index c0477e71db519..4f4667fe65a16 100644 --- a/tests/cases/conformance/types/rest/objectRestNegative.ts +++ b/tests/cases/conformance/types/rest/objectRestNegative.ts @@ -17,4 +17,4 @@ function generic(t: T) { let rest: { b: string } ({a, ...rest.b + rest.b} = o); -var noContextualType = ({ aNumber = 12, ...implicitlyAny }) => aNumber + implicitlyAny.anythingGoes; +var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes;