From 5cea46c5376f244980207eff22436742e27417cc Mon Sep 17 00:00:00 2001 From: TypeScript Bot Date: Tue, 29 Jun 2021 06:05:59 +0000 Subject: [PATCH 1/6] Update package-lock.json --- package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 436d3660f41..f11e065217f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -325,9 +325,9 @@ } }, "@octokit/openapi-types": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.3.5.tgz", - "integrity": "sha512-6bm5lzGDOeSnWHM5W8OZ86RD2KpchynU+/Qlm5hNEFjfLDhwfAY2lSe68YRUEYFGlxSHe0HmakyhvmtWoD3Zog==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.4.0.tgz", + "integrity": "sha512-V2qNML1knHjrjTJcIIvhYZSTkvtSAoQpNEX8y0ykTJI8vOQPqIh0y6Jf9EU6c/y+v0c9+LeC1acwLQh1xo96MA==", "dev": true }, "@octokit/plugin-paginate-rest": { @@ -401,12 +401,12 @@ } }, "@octokit/types": { - "version": "6.16.7", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.16.7.tgz", - "integrity": "sha512-OuQELiwIKeDySgNID52vm33wDRc2aaX8lKYgAw9Hmw939ITow1HspT8/AH3M3jgGFUMDmHlMNBNEmH7xV7ggXQ==", + "version": "6.17.1", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.17.1.tgz", + "integrity": "sha512-x1RDwjjSzGHK8hfwyNa4Gz0t5YtwUfIxEtejFpm2cjH1gMMk6XDv8La3gUAPzYpDgdzTEF8Lpz+7BGv9aZR/0w==", "dev": true, "requires": { - "@octokit/openapi-types": "^7.3.5" + "@octokit/openapi-types": "^7.4.0" } }, "@types/browserify": { From f47ddbc3b0c6421c38b18e56f8da88434a473c8d Mon Sep 17 00:00:00 2001 From: Eli Barzilay Date: Fri, 25 Jun 2021 13:45:43 -0400 Subject: [PATCH 2/6] Fix bad line number assertion in `ScriptInfo.positionToLineOffset` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the line number side of ecddf8468f (from #21924, fixing #21818). But the code is slightly improved for both cases: instead of testing that `leaf` is defined, check whether `lineCount` is zero, and if it is, return `〈1,0〉` for the one-based line and zero-based column numbers. (The requirement of `lineCount > 0` is also seen in the fact that `lineNumberToInfo` expects a "*One*BasedLine" argument.) I've stared at this code way too much, since I think that there is something more fundamentally wrong here. E.g., `EditWalker` only `push`es to `startPath` but never pops even a `children`-less node that is left after deleting the whole contents. But I can't figure out the overall structure, which is also why the test that I added is not great (see the comment there; also, #21924 is dealing with the same problem and didn't add a test). Fixes #44518. --- src/server/scriptVersionCache.ts | 14 ++++++++------ src/testRunner/unittests/tsserver/versionCache.ts | 12 ++++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/server/scriptVersionCache.ts b/src/server/scriptVersionCache.ts index db697cfb1ab..c9adc3427ee 100644 --- a/src/server/scriptVersionCache.ts +++ b/src/server/scriptVersionCache.ts @@ -67,10 +67,8 @@ namespace ts.server { } const lm = LineIndex.linesFromText(insertedText); const lines = lm.lines; - if (lines.length > 1) { - if (lines[lines.length - 1] === "") { - lines.pop(); - } + if (lines.length > 1 && lines[lines.length - 1] === "") { + lines.pop(); } let branchParent: LineNode | undefined; let lastZeroCount: LineCollection | undefined; @@ -683,8 +681,12 @@ namespace ts.server { } // Skipped all children - const { leaf } = this.lineNumberToInfo(this.lineCount(), 0); - return { oneBasedLine: this.lineCount(), zeroBasedColumn: leaf ? leaf.charCount() : 0, lineText: undefined }; + const lineCount = this.lineCount(); + if (lineCount === 0) { // it's empty! (and lineNumberToInfo expects a one-based line) + return { oneBasedLine: 1, zeroBasedColumn: 0, lineText: undefined }; + } + const leaf = Debug.checkDefined(this.lineNumberToInfo(lineCount, 0).leaf); + return { oneBasedLine: lineCount, zeroBasedColumn: leaf.charCount(), lineText: undefined }; } /** diff --git a/src/testRunner/unittests/tsserver/versionCache.ts b/src/testRunner/unittests/tsserver/versionCache.ts index 60eaa6ca42e..d779ba1fdd2 100644 --- a/src/testRunner/unittests/tsserver/versionCache.ts +++ b/src/testRunner/unittests/tsserver/versionCache.ts @@ -52,6 +52,18 @@ var q:Point=p;`; assert.deepEqual(lineIndex.positionToLineOffset(0), { line: 1, offset: 1 }); }); + it("handles emptying whole file (GH#44518)", () => { + // See below for the main thing that this tests; it would be better to have a test + // that uses `ScriptInfo.positionToLineOffset` but I couldn't find away to do that + const { lines } = server.LineIndex.linesFromText("function foo() {\n\ndsa\n\n}\n\nfo(dsa\n\n\n "); + const lineIndex = new server.LineIndex(); + lineIndex.load(lines); + const snapshot = lineIndex.edit(0, 39); + assert.equal(snapshot.getText(0, snapshot.getLength()), ""); + // line must always be >=1, otherwise the failIfInvalidLocation(location) assertion in ScriptInfo.positionToLineOffset will fail + assert.deepEqual(snapshot.positionToLineOffset(0), { line: 1, offset: 1 }); + }); + it(`change 9 1 0 1 {"y"}`, () => { validateEditAtLineCharIndex(9, 1, 0, "y"); }); From fdc31baffeb9185b1e81ffa9e20556532f15f735 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Tue, 29 Jun 2021 19:53:35 +0100 Subject: [PATCH 3/6] Fix types in the boolean trivial lint rule (#44801) --- scripts/eslint/rules/boolean-trivia.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/eslint/rules/boolean-trivia.ts b/scripts/eslint/rules/boolean-trivia.ts index 822f0b844cb..cf1fc1f73e4 100644 --- a/scripts/eslint/rules/boolean-trivia.ts +++ b/scripts/eslint/rules/boolean-trivia.ts @@ -23,7 +23,7 @@ export = createRule({ const sourceCodeText = sourceCode.getText(); const isSetOrAssert = (name: string): boolean => name.startsWith("set") || name.startsWith("assert"); - const isTrivia = (node: TSESTree.CallExpressionArgument): boolean => { + const isTrivia = (node: TSESTree.Node): boolean => { if (node.type === AST_NODE_TYPES.Identifier) { return node.name === "undefined"; } @@ -69,7 +69,7 @@ export = createRule({ return false; }; - const checkArg = (node: TSESTree.CallExpressionArgument): void => { + const checkArg = (node: TSESTree.Node): void => { if (!isTrivia(node)) { return; } From 114f68cd3d78bdf540c7870ed2ed4ca5728238bb Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Wed, 30 Jun 2021 00:11:35 +0300 Subject: [PATCH 4/6] fix(44725): handle this parameter in tagged template call (#44734) --- src/compiler/checker.ts | 6 ++-- .../reference/thisTypeInTaggedTemplateCall.js | 19 ++++++++++++ .../thisTypeInTaggedTemplateCall.symbols | 27 +++++++++++++++++ .../thisTypeInTaggedTemplateCall.types | 30 +++++++++++++++++++ .../thisType/thisTypeInTaggedTemplateCall.ts | 10 +++++++ 5 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/thisTypeInTaggedTemplateCall.js create mode 100644 tests/baselines/reference/thisTypeInTaggedTemplateCall.symbols create mode 100644 tests/baselines/reference/thisTypeInTaggedTemplateCall.types create mode 100644 tests/cases/conformance/types/thisType/thisTypeInTaggedTemplateCall.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 37a1135d2d4..eb00c3708d1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28724,8 +28724,10 @@ namespace ts { * Returns the this argument in calls like x.f(...) and x[f](...). Undefined otherwise. */ function getThisArgumentOfCall(node: CallLikeExpression): LeftHandSideExpression | undefined { - if (node.kind === SyntaxKind.CallExpression) { - const callee = skipOuterExpressions(node.expression); + const expression = node.kind === SyntaxKind.CallExpression ? node.expression : + node.kind === SyntaxKind.TaggedTemplateExpression ? node.tag : undefined; + if (expression) { + const callee = skipOuterExpressions(expression); if (isAccessExpression(callee)) { return callee.expression; } diff --git a/tests/baselines/reference/thisTypeInTaggedTemplateCall.js b/tests/baselines/reference/thisTypeInTaggedTemplateCall.js new file mode 100644 index 00000000000..de5c21307cf --- /dev/null +++ b/tests/baselines/reference/thisTypeInTaggedTemplateCall.js @@ -0,0 +1,19 @@ +//// [thisTypeInTaggedTemplateCall.ts] +class Foo { + static m(this: new () => T, strings: TemplateStringsArray | string) { + return new this() + } +} + +Foo.m`test`; +(Foo.m)`test`; + + +//// [thisTypeInTaggedTemplateCall.js] +class Foo { + static m(strings) { + return new this(); + } +} +Foo.m `test`; +(Foo.m) `test`; diff --git a/tests/baselines/reference/thisTypeInTaggedTemplateCall.symbols b/tests/baselines/reference/thisTypeInTaggedTemplateCall.symbols new file mode 100644 index 00000000000..4bb013c4da1 --- /dev/null +++ b/tests/baselines/reference/thisTypeInTaggedTemplateCall.symbols @@ -0,0 +1,27 @@ +=== tests/cases/conformance/types/thisType/thisTypeInTaggedTemplateCall.ts === +class Foo { +>Foo : Symbol(Foo, Decl(thisTypeInTaggedTemplateCall.ts, 0, 0)) + + static m(this: new () => T, strings: TemplateStringsArray | string) { +>m : Symbol(Foo.m, Decl(thisTypeInTaggedTemplateCall.ts, 0, 11)) +>T : Symbol(T, Decl(thisTypeInTaggedTemplateCall.ts, 1, 13)) +>this : Symbol(this, Decl(thisTypeInTaggedTemplateCall.ts, 1, 16)) +>T : Symbol(T, Decl(thisTypeInTaggedTemplateCall.ts, 1, 13)) +>strings : Symbol(strings, Decl(thisTypeInTaggedTemplateCall.ts, 1, 34)) +>TemplateStringsArray : Symbol(TemplateStringsArray, Decl(lib.es5.d.ts, --, --)) + + return new this() +>this : Symbol(this, Decl(thisTypeInTaggedTemplateCall.ts, 1, 16)) + } +} + +Foo.m`test`; +>Foo.m : Symbol(Foo.m, Decl(thisTypeInTaggedTemplateCall.ts, 0, 11)) +>Foo : Symbol(Foo, Decl(thisTypeInTaggedTemplateCall.ts, 0, 0)) +>m : Symbol(Foo.m, Decl(thisTypeInTaggedTemplateCall.ts, 0, 11)) + +(Foo.m)`test`; +>Foo.m : Symbol(Foo.m, Decl(thisTypeInTaggedTemplateCall.ts, 0, 11)) +>Foo : Symbol(Foo, Decl(thisTypeInTaggedTemplateCall.ts, 0, 0)) +>m : Symbol(Foo.m, Decl(thisTypeInTaggedTemplateCall.ts, 0, 11)) + diff --git a/tests/baselines/reference/thisTypeInTaggedTemplateCall.types b/tests/baselines/reference/thisTypeInTaggedTemplateCall.types new file mode 100644 index 00000000000..4c64229924e --- /dev/null +++ b/tests/baselines/reference/thisTypeInTaggedTemplateCall.types @@ -0,0 +1,30 @@ +=== tests/cases/conformance/types/thisType/thisTypeInTaggedTemplateCall.ts === +class Foo { +>Foo : Foo + + static m(this: new () => T, strings: TemplateStringsArray | string) { +>m : (this: new () => T, strings: TemplateStringsArray | string) => T +>this : new () => T +>strings : string | TemplateStringsArray + + return new this() +>new this() : T +>this : new () => T + } +} + +Foo.m`test`; +>Foo.m`test` : Foo +>Foo.m : (this: new () => T, strings: string | TemplateStringsArray) => T +>Foo : typeof Foo +>m : (this: new () => T, strings: string | TemplateStringsArray) => T +>`test` : "test" + +(Foo.m)`test`; +>(Foo.m)`test` : Foo +>(Foo.m) : (this: new () => T, strings: string | TemplateStringsArray) => T +>Foo.m : (this: new () => T, strings: string | TemplateStringsArray) => T +>Foo : typeof Foo +>m : (this: new () => T, strings: string | TemplateStringsArray) => T +>`test` : "test" + diff --git a/tests/cases/conformance/types/thisType/thisTypeInTaggedTemplateCall.ts b/tests/cases/conformance/types/thisType/thisTypeInTaggedTemplateCall.ts new file mode 100644 index 00000000000..c46933329b6 --- /dev/null +++ b/tests/cases/conformance/types/thisType/thisTypeInTaggedTemplateCall.ts @@ -0,0 +1,10 @@ +// @target: esnext + +class Foo { + static m(this: new () => T, strings: TemplateStringsArray | string) { + return new this() + } +} + +Foo.m`test`; +(Foo.m)`test`; From 4c19873b648ee6bfe011ec1dd5fb4a33b3c75b89 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 29 Jun 2021 14:53:07 -0700 Subject: [PATCH 5/6] Validate symbol-named properties against symbol index signatures (#44815) * Validate symbols against both symbol and string index signatures * Add tests * Accept new baselines --- src/compiler/checker.ts | 6 ++- .../reference/indexSignatures1.errors.txt | 21 ++++++++- tests/baselines/reference/indexSignatures1.js | 33 ++++++++++++++ .../reference/indexSignatures1.symbols | 39 ++++++++++++++++ .../reference/indexSignatures1.types | 44 +++++++++++++++++++ .../types/members/indexSignatures1.ts | 14 ++++++ 6 files changed, 155 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index eb00c3708d1..b64606d63b9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12106,7 +12106,7 @@ namespace ts { } function getApplicableIndexInfoForName(type: Type, name: __String): IndexInfo | undefined { - return getApplicableIndexInfo(type, getStringLiteralType(unescapeLeadingUnderscores(name))); + return getApplicableIndexInfo(type, isLateBoundName(name) ? esSymbolType : getStringLiteralType(unescapeLeadingUnderscores(name))); } // Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual @@ -27121,8 +27121,12 @@ namespace ts { */ function isKnownProperty(targetType: Type, name: __String, isComparingJsxAttributes: boolean): boolean { if (targetType.flags & TypeFlags.Object) { + // For backwards compatibility a symbol-named property is satisfied by a string index signature. This + // is incorrect and inconsistent with element access expressions, where it is an error, so eventually + // we should remove this exception. if (getPropertyOfObjectType(targetType, name) || getApplicableIndexInfoForName(targetType, name) || + isLateBoundName(name) && getIndexInfoOfType(targetType, stringType) || isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) { // For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known. return true; diff --git a/tests/baselines/reference/indexSignatures1.errors.txt b/tests/baselines/reference/indexSignatures1.errors.txt index 4d0310333c1..1a3ff537203 100644 --- a/tests/baselines/reference/indexSignatures1.errors.txt +++ b/tests/baselines/reference/indexSignatures1.errors.txt @@ -68,9 +68,11 @@ tests/cases/conformance/types/members/indexSignatures1.ts(281,35): error TS2322: Object literal may only specify known properties, and ''someKey'' does not exist in type 'PseudoDeclaration'. tests/cases/conformance/types/members/indexSignatures1.ts(286,7): error TS2322: Type '"two"' is not assignable to type '`/${string}`'. tests/cases/conformance/types/members/indexSignatures1.ts(289,7): error TS2322: Type 'number' is not assignable to type 'PathsObject'. +tests/cases/conformance/types/members/indexSignatures1.ts(312,43): error TS2322: Type '{ [sym]: string; }' is not assignable to type '{ [key: number]: string; }'. + Object literal may only specify known properties, and '[sym]' does not exist in type '{ [key: number]: string; }'. -==== tests/cases/conformance/types/members/indexSignatures1.ts (49 errors) ==== +==== tests/cases/conformance/types/members/indexSignatures1.ts (50 errors) ==== // Symbol index signature checking const sym = Symbol(); @@ -488,4 +490,21 @@ tests/cases/conformance/types/members/indexSignatures1.ts(289,7): error TS2322: const a: A = { [id]: 'test' } let aid = a[id]; + + // Repro from #44793 + + interface AA { + a?: string; + b?: number; + [key: symbol]: string; + } + + const aa: AA = { [sym]: '123' }; + + const obj1: { [key: symbol]: string } = { [sym]: 'hello '}; + const obj2: { [key: string]: string } = { [sym]: 'hello '}; // Permitted for backwards compatibility + const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error + ~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ [sym]: string; }' is not assignable to type '{ [key: number]: string; }'. +!!! error TS2322: Object literal may only specify known properties, and '[sym]' does not exist in type '{ [key: number]: string; }'. \ No newline at end of file diff --git a/tests/baselines/reference/indexSignatures1.js b/tests/baselines/reference/indexSignatures1.js index 1eb625374e6..0202d3df3ed 100644 --- a/tests/baselines/reference/indexSignatures1.js +++ b/tests/baselines/reference/indexSignatures1.js @@ -297,6 +297,20 @@ type A = Record; const a: A = { [id]: 'test' } let aid = a[id]; + +// Repro from #44793 + +interface AA { + a?: string; + b?: number; + [key: symbol]: string; +} + +const aa: AA = { [sym]: '123' }; + +const obj1: { [key: symbol]: string } = { [sym]: 'hello '}; +const obj2: { [key: string]: string } = { [sym]: 'hello '}; // Permitted for backwards compatibility +const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error //// [indexSignatures1.js] @@ -457,6 +471,10 @@ const pathObject = 123; // Error const id = '0000-0000-0000-0001'; const a = { [id]: 'test' }; let aid = a[id]; +const aa = { [sym]: '123' }; +const obj1 = { [sym]: 'hello ' }; +const obj2 = { [sym]: 'hello ' }; // Permitted for backwards compatibility +const obj3 = { [sym]: 'hello ' }; // Error //// [indexSignatures1.d.ts] @@ -627,3 +645,18 @@ declare const id: IdType; declare type A = Record; declare const a: A; declare let aid: string; +interface AA { + a?: string; + b?: number; + [key: symbol]: string; +} +declare const aa: AA; +declare const obj1: { + [key: symbol]: string; +}; +declare const obj2: { + [key: string]: string; +}; +declare const obj3: { + [key: number]: string; +}; diff --git a/tests/baselines/reference/indexSignatures1.symbols b/tests/baselines/reference/indexSignatures1.symbols index d2879177249..e5f0fea8150 100644 --- a/tests/baselines/reference/indexSignatures1.symbols +++ b/tests/baselines/reference/indexSignatures1.symbols @@ -860,3 +860,42 @@ let aid = a[id]; >a : Symbol(a, Decl(indexSignatures1.ts, 295, 5)) >id : Symbol(id, Decl(indexSignatures1.ts, 291, 5)) +// Repro from #44793 + +interface AA { +>AA : Symbol(AA, Decl(indexSignatures1.ts, 297, 16)) + + a?: string; +>a : Symbol(AA.a, Decl(indexSignatures1.ts, 301, 14)) + + b?: number; +>b : Symbol(AA.b, Decl(indexSignatures1.ts, 302, 15)) + + [key: symbol]: string; +>key : Symbol(key, Decl(indexSignatures1.ts, 304, 5)) +} + +const aa: AA = { [sym]: '123' }; +>aa : Symbol(aa, Decl(indexSignatures1.ts, 307, 5)) +>AA : Symbol(AA, Decl(indexSignatures1.ts, 297, 16)) +>[sym] : Symbol([sym], Decl(indexSignatures1.ts, 307, 16)) +>sym : Symbol(sym, Decl(indexSignatures1.ts, 2, 5)) + +const obj1: { [key: symbol]: string } = { [sym]: 'hello '}; +>obj1 : Symbol(obj1, Decl(indexSignatures1.ts, 309, 5)) +>key : Symbol(key, Decl(indexSignatures1.ts, 309, 15)) +>[sym] : Symbol([sym], Decl(indexSignatures1.ts, 309, 41)) +>sym : Symbol(sym, Decl(indexSignatures1.ts, 2, 5)) + +const obj2: { [key: string]: string } = { [sym]: 'hello '}; // Permitted for backwards compatibility +>obj2 : Symbol(obj2, Decl(indexSignatures1.ts, 310, 5)) +>key : Symbol(key, Decl(indexSignatures1.ts, 310, 15)) +>[sym] : Symbol([sym], Decl(indexSignatures1.ts, 310, 41)) +>sym : Symbol(sym, Decl(indexSignatures1.ts, 2, 5)) + +const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error +>obj3 : Symbol(obj3, Decl(indexSignatures1.ts, 311, 5)) +>key : Symbol(key, Decl(indexSignatures1.ts, 311, 15)) +>[sym] : Symbol([sym], Decl(indexSignatures1.ts, 311, 41)) +>sym : Symbol(sym, Decl(indexSignatures1.ts, 2, 5)) + diff --git a/tests/baselines/reference/indexSignatures1.types b/tests/baselines/reference/indexSignatures1.types index 1e73c76e244..b543739f238 100644 --- a/tests/baselines/reference/indexSignatures1.types +++ b/tests/baselines/reference/indexSignatures1.types @@ -1007,3 +1007,47 @@ let aid = a[id]; >a : A >id : `${number}-${number}-${number}-${number}` +// Repro from #44793 + +interface AA { + a?: string; +>a : string | undefined + + b?: number; +>b : number | undefined + + [key: symbol]: string; +>key : symbol +} + +const aa: AA = { [sym]: '123' }; +>aa : AA +>{ [sym]: '123' } : { [sym]: string; } +>[sym] : string +>sym : unique symbol +>'123' : "123" + +const obj1: { [key: symbol]: string } = { [sym]: 'hello '}; +>obj1 : { [key: symbol]: string; } +>key : symbol +>{ [sym]: 'hello '} : { [sym]: string; } +>[sym] : string +>sym : unique symbol +>'hello ' : "hello " + +const obj2: { [key: string]: string } = { [sym]: 'hello '}; // Permitted for backwards compatibility +>obj2 : { [key: string]: string; } +>key : string +>{ [sym]: 'hello '} : { [sym]: string; } +>[sym] : string +>sym : unique symbol +>'hello ' : "hello " + +const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error +>obj3 : { [key: number]: string; } +>key : number +>{ [sym]: 'hello '} : { [sym]: string; } +>[sym] : string +>sym : unique symbol +>'hello ' : "hello " + diff --git a/tests/cases/conformance/types/members/indexSignatures1.ts b/tests/cases/conformance/types/members/indexSignatures1.ts index a35471bdbfd..2d86c237681 100644 --- a/tests/cases/conformance/types/members/indexSignatures1.ts +++ b/tests/cases/conformance/types/members/indexSignatures1.ts @@ -300,3 +300,17 @@ type A = Record; const a: A = { [id]: 'test' } let aid = a[id]; + +// Repro from #44793 + +interface AA { + a?: string; + b?: number; + [key: symbol]: string; +} + +const aa: AA = { [sym]: '123' }; + +const obj1: { [key: symbol]: string } = { [sym]: 'hello '}; +const obj2: { [key: string]: string } = { [sym]: 'hello '}; // Permitted for backwards compatibility +const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error From 5c8d76347c4face74e708624c424e65cbeee16d7 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Wed, 30 Jun 2021 02:56:45 +0300 Subject: [PATCH 6/6] fix(44448): disallow 'delete' operator for optional properties (#44612) --- src/compiler/checker.ts | 5 +- src/testRunner/compilerRunner.ts | 1 + ...ionMustBeOptional(strict=false).errors.txt | 3 +- ...eExpressionMustBeOptional(strict=false).js | 3 +- ...sionMustBeOptional(strict=true).errors.txt | 3 +- ...teExpressionMustBeOptional(strict=true).js | 3 +- ...actoptionalpropertytypes=false).errors.txt | 53 +++++++ ...Types(exactoptionalpropertytypes=false).js | 58 ++++++++ ...(exactoptionalpropertytypes=false).symbols | 118 +++++++++++++++ ...es(exactoptionalpropertytypes=false).types | 137 ++++++++++++++++++ ...xactoptionalpropertytypes=true).errors.txt | 65 +++++++++ ...yTypes(exactoptionalpropertytypes=true).js | 58 ++++++++ ...s(exactoptionalpropertytypes=true).symbols | 118 +++++++++++++++ ...pes(exactoptionalpropertytypes=true).types | 137 ++++++++++++++++++ .../deleteExpressionMustBeOptional.ts | 84 +++++------ ...stBeOptional_exactOptionalPropertyTypes.ts | 43 ++++++ 16 files changed, 841 insertions(+), 48 deletions(-) create mode 100644 tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).errors.txt create mode 100644 tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).js create mode 100644 tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).symbols create mode 100644 tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).types create mode 100644 tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).errors.txt create mode 100644 tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).js create mode 100644 tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).symbols create mode 100644 tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).types create mode 100644 tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b64606d63b9..b1d2befee7e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -31409,8 +31409,9 @@ namespace ts { } function checkDeleteExpressionMustBeOptional(expr: AccessExpression, type: Type) { - const AnyOrUnknownOrNeverFlags = TypeFlags.AnyOrUnknown | TypeFlags.Never; - if (strictNullChecks && !(type.flags & AnyOrUnknownOrNeverFlags) && !(getFalsyFlags(type) & TypeFlags.Undefined)) { + if (strictNullChecks && + !(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Never)) && + !(exactOptionalPropertyTypes ? 0 : getFalsyFlags(type) & TypeFlags.Undefined)) { error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_optional); } } diff --git a/src/testRunner/compilerRunner.ts b/src/testRunner/compilerRunner.ts index 298c84ec8c7..0a899cd8e8e 100644 --- a/src/testRunner/compilerRunner.ts +++ b/src/testRunner/compilerRunner.ts @@ -136,6 +136,7 @@ namespace Harness { "skipDefaultLibCheck", "preserveConstEnums", "skipLibCheck", + "exactOptionalPropertyTypes" ]; private fileName: string; private justName: string; diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).errors.txt b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).errors.txt index 8a876cb6350..2ffd2ef4338 100644 --- a/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).errors.txt +++ b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).errors.txt @@ -43,4 +43,5 @@ tests/cases/compiler/deleteExpressionMustBeOptional.ts(34,10): error TS2339: Pro delete a.b delete b.a - delete b.b \ No newline at end of file + delete b.b + \ No newline at end of file diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).js b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).js index 268c76175bf..228fd713d10 100644 --- a/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).js +++ b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).js @@ -38,7 +38,8 @@ delete a.a delete a.b delete b.a -delete b.b +delete b.b + //// [deleteExpressionMustBeOptional.js] delete f.a; diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).errors.txt b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).errors.txt index b1cabc96009..2a493910005 100644 --- a/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).errors.txt +++ b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).errors.txt @@ -49,4 +49,5 @@ tests/cases/compiler/deleteExpressionMustBeOptional.ts(34,10): error TS2339: Pro delete a.b delete b.a - delete b.b \ No newline at end of file + delete b.b + \ No newline at end of file diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).js b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).js index ca81456b4f4..5cf8d6da563 100644 --- a/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).js +++ b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).js @@ -38,7 +38,8 @@ delete a.a delete a.b delete b.a -delete b.b +delete b.b + //// [deleteExpressionMustBeOptional.js] "use strict"; diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).errors.txt b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).errors.txt new file mode 100644 index 00000000000..7953479e490 --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).errors.txt @@ -0,0 +1,53 @@ +tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts(25,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts(27,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts(34,10): error TS2339: Property 'j' does not exist on type 'Foo'. + + +==== tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts (3 errors) ==== + interface Foo { + a: number + b: number | undefined + c: number | null + d?: number + e: number | undefined | null + f?: number | undefined | null + g: unknown + h: any + i: never + } + + interface AA { + [s: string]: number + } + + type BB = { + [P in keyof any]: number + } + + declare const f: Foo + declare const a: AA + declare const b: BB + + delete f.a + ~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete f.b + delete f.c + ~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete f.d + delete f.e + delete f.f + delete f.g + delete f.h + delete f.i + delete f.j + ~ +!!! error TS2339: Property 'j' does not exist on type 'Foo'. + + delete a.a + delete a.b + + delete b.a + delete b.b + \ No newline at end of file diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).js b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).js new file mode 100644 index 00000000000..2a4b0326cb8 --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).js @@ -0,0 +1,58 @@ +//// [deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts] +interface Foo { + a: number + b: number | undefined + c: number | null + d?: number + e: number | undefined | null + f?: number | undefined | null + g: unknown + h: any + i: never +} + +interface AA { + [s: string]: number +} + +type BB = { + [P in keyof any]: number +} + +declare const f: Foo +declare const a: AA +declare const b: BB + +delete f.a +delete f.b +delete f.c +delete f.d +delete f.e +delete f.f +delete f.g +delete f.h +delete f.i +delete f.j + +delete a.a +delete a.b + +delete b.a +delete b.b + + +//// [deleteExpressionMustBeOptional_exactOptionalPropertyTypes.js] +delete f.a; +delete f.b; +delete f.c; +delete f.d; +delete f.e; +delete f.f; +delete f.g; +delete f.h; +delete f.i; +delete f.j; +delete a.a; +delete a.b; +delete b.a; +delete b.b; diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).symbols b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).symbols new file mode 100644 index 00000000000..f03e4c4ba62 --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).symbols @@ -0,0 +1,118 @@ +=== tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts === +interface Foo { +>Foo : Symbol(Foo, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 0, 0)) + + a: number +>a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 0, 15)) + + b: number | undefined +>b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 1, 13)) + + c: number | null +>c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 2, 25)) + + d?: number +>d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 3, 20)) + + e: number | undefined | null +>e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 4, 14)) + + f?: number | undefined | null +>f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 5, 32)) + + g: unknown +>g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 6, 33)) + + h: any +>h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 7, 14)) + + i: never +>i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 8, 10)) +} + +interface AA { +>AA : Symbol(AA, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 10, 1)) + + [s: string]: number +>s : Symbol(s, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 13, 5)) +} + +type BB = { +>BB : Symbol(BB, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 14, 1)) + + [P in keyof any]: number +>P : Symbol(P, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 17, 5)) +} + +declare const f: Foo +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>Foo : Symbol(Foo, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 0, 0)) + +declare const a: AA +>a : Symbol(a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 21, 13)) +>AA : Symbol(AA, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 10, 1)) + +declare const b: BB +>b : Symbol(b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 22, 13)) +>BB : Symbol(BB, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 14, 1)) + +delete f.a +>f.a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 0, 15)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 0, 15)) + +delete f.b +>f.b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 1, 13)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 1, 13)) + +delete f.c +>f.c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 2, 25)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 2, 25)) + +delete f.d +>f.d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 3, 20)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 3, 20)) + +delete f.e +>f.e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 4, 14)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 4, 14)) + +delete f.f +>f.f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 5, 32)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 5, 32)) + +delete f.g +>f.g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 6, 33)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 6, 33)) + +delete f.h +>f.h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 7, 14)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 7, 14)) + +delete f.i +>f.i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 8, 10)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 8, 10)) + +delete f.j +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) + +delete a.a +>a : Symbol(a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 21, 13)) + +delete a.b +>a : Symbol(a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 21, 13)) + +delete b.a +>b : Symbol(b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 22, 13)) + +delete b.b +>b : Symbol(b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 22, 13)) + diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).types b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).types new file mode 100644 index 00000000000..13436510af0 --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=false).types @@ -0,0 +1,137 @@ +=== tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts === +interface Foo { + a: number +>a : number + + b: number | undefined +>b : number | undefined + + c: number | null +>c : number | null +>null : null + + d?: number +>d : number | undefined + + e: number | undefined | null +>e : number | null | undefined +>null : null + + f?: number | undefined | null +>f : number | null | undefined +>null : null + + g: unknown +>g : unknown + + h: any +>h : any + + i: never +>i : never +} + +interface AA { + [s: string]: number +>s : string +} + +type BB = { +>BB : BB + + [P in keyof any]: number +} + +declare const f: Foo +>f : Foo + +declare const a: AA +>a : AA + +declare const b: BB +>b : BB + +delete f.a +>delete f.a : boolean +>f.a : number +>f : Foo +>a : number + +delete f.b +>delete f.b : boolean +>f.b : number | undefined +>f : Foo +>b : number | undefined + +delete f.c +>delete f.c : boolean +>f.c : number | null +>f : Foo +>c : number | null + +delete f.d +>delete f.d : boolean +>f.d : number | undefined +>f : Foo +>d : number | undefined + +delete f.e +>delete f.e : boolean +>f.e : number | null | undefined +>f : Foo +>e : number | null | undefined + +delete f.f +>delete f.f : boolean +>f.f : number | null | undefined +>f : Foo +>f : number | null | undefined + +delete f.g +>delete f.g : boolean +>f.g : unknown +>f : Foo +>g : unknown + +delete f.h +>delete f.h : boolean +>f.h : any +>f : Foo +>h : any + +delete f.i +>delete f.i : boolean +>f.i : never +>f : Foo +>i : never + +delete f.j +>delete f.j : boolean +>f.j : any +>f : Foo +>j : any + +delete a.a +>delete a.a : boolean +>a.a : number +>a : AA +>a : number + +delete a.b +>delete a.b : boolean +>a.b : number +>a : AA +>b : number + +delete b.a +>delete b.a : boolean +>b.a : number +>b : BB +>a : number + +delete b.b +>delete b.b : boolean +>b.b : number +>b : BB +>b : number + diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).errors.txt b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).errors.txt new file mode 100644 index 00000000000..300d2370355 --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).errors.txt @@ -0,0 +1,65 @@ +tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts(25,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts(26,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts(27,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts(28,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts(29,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts(30,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts(34,10): error TS2339: Property 'j' does not exist on type 'Foo'. + + +==== tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts (7 errors) ==== + interface Foo { + a: number + b: number | undefined + c: number | null + d?: number + e: number | undefined | null + f?: number | undefined | null + g: unknown + h: any + i: never + } + + interface AA { + [s: string]: number + } + + type BB = { + [P in keyof any]: number + } + + declare const f: Foo + declare const a: AA + declare const b: BB + + delete f.a + ~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete f.b + ~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete f.c + ~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete f.d + ~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete f.e + ~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete f.f + ~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete f.g + delete f.h + delete f.i + delete f.j + ~ +!!! error TS2339: Property 'j' does not exist on type 'Foo'. + + delete a.a + delete a.b + + delete b.a + delete b.b + \ No newline at end of file diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).js b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).js new file mode 100644 index 00000000000..2a4b0326cb8 --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).js @@ -0,0 +1,58 @@ +//// [deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts] +interface Foo { + a: number + b: number | undefined + c: number | null + d?: number + e: number | undefined | null + f?: number | undefined | null + g: unknown + h: any + i: never +} + +interface AA { + [s: string]: number +} + +type BB = { + [P in keyof any]: number +} + +declare const f: Foo +declare const a: AA +declare const b: BB + +delete f.a +delete f.b +delete f.c +delete f.d +delete f.e +delete f.f +delete f.g +delete f.h +delete f.i +delete f.j + +delete a.a +delete a.b + +delete b.a +delete b.b + + +//// [deleteExpressionMustBeOptional_exactOptionalPropertyTypes.js] +delete f.a; +delete f.b; +delete f.c; +delete f.d; +delete f.e; +delete f.f; +delete f.g; +delete f.h; +delete f.i; +delete f.j; +delete a.a; +delete a.b; +delete b.a; +delete b.b; diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).symbols b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).symbols new file mode 100644 index 00000000000..f03e4c4ba62 --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).symbols @@ -0,0 +1,118 @@ +=== tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts === +interface Foo { +>Foo : Symbol(Foo, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 0, 0)) + + a: number +>a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 0, 15)) + + b: number | undefined +>b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 1, 13)) + + c: number | null +>c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 2, 25)) + + d?: number +>d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 3, 20)) + + e: number | undefined | null +>e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 4, 14)) + + f?: number | undefined | null +>f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 5, 32)) + + g: unknown +>g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 6, 33)) + + h: any +>h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 7, 14)) + + i: never +>i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 8, 10)) +} + +interface AA { +>AA : Symbol(AA, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 10, 1)) + + [s: string]: number +>s : Symbol(s, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 13, 5)) +} + +type BB = { +>BB : Symbol(BB, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 14, 1)) + + [P in keyof any]: number +>P : Symbol(P, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 17, 5)) +} + +declare const f: Foo +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>Foo : Symbol(Foo, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 0, 0)) + +declare const a: AA +>a : Symbol(a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 21, 13)) +>AA : Symbol(AA, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 10, 1)) + +declare const b: BB +>b : Symbol(b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 22, 13)) +>BB : Symbol(BB, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 14, 1)) + +delete f.a +>f.a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 0, 15)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 0, 15)) + +delete f.b +>f.b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 1, 13)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 1, 13)) + +delete f.c +>f.c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 2, 25)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 2, 25)) + +delete f.d +>f.d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 3, 20)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 3, 20)) + +delete f.e +>f.e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 4, 14)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 4, 14)) + +delete f.f +>f.f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 5, 32)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 5, 32)) + +delete f.g +>f.g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 6, 33)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 6, 33)) + +delete f.h +>f.h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 7, 14)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 7, 14)) + +delete f.i +>f.i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 8, 10)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) +>i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 8, 10)) + +delete f.j +>f : Symbol(f, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 20, 13)) + +delete a.a +>a : Symbol(a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 21, 13)) + +delete a.b +>a : Symbol(a, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 21, 13)) + +delete b.a +>b : Symbol(b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 22, 13)) + +delete b.b +>b : Symbol(b, Decl(deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts, 22, 13)) + diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).types b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).types new file mode 100644 index 00000000000..13436510af0 --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional_exactOptionalPropertyTypes(exactoptionalpropertytypes=true).types @@ -0,0 +1,137 @@ +=== tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts === +interface Foo { + a: number +>a : number + + b: number | undefined +>b : number | undefined + + c: number | null +>c : number | null +>null : null + + d?: number +>d : number | undefined + + e: number | undefined | null +>e : number | null | undefined +>null : null + + f?: number | undefined | null +>f : number | null | undefined +>null : null + + g: unknown +>g : unknown + + h: any +>h : any + + i: never +>i : never +} + +interface AA { + [s: string]: number +>s : string +} + +type BB = { +>BB : BB + + [P in keyof any]: number +} + +declare const f: Foo +>f : Foo + +declare const a: AA +>a : AA + +declare const b: BB +>b : BB + +delete f.a +>delete f.a : boolean +>f.a : number +>f : Foo +>a : number + +delete f.b +>delete f.b : boolean +>f.b : number | undefined +>f : Foo +>b : number | undefined + +delete f.c +>delete f.c : boolean +>f.c : number | null +>f : Foo +>c : number | null + +delete f.d +>delete f.d : boolean +>f.d : number | undefined +>f : Foo +>d : number | undefined + +delete f.e +>delete f.e : boolean +>f.e : number | null | undefined +>f : Foo +>e : number | null | undefined + +delete f.f +>delete f.f : boolean +>f.f : number | null | undefined +>f : Foo +>f : number | null | undefined + +delete f.g +>delete f.g : boolean +>f.g : unknown +>f : Foo +>g : unknown + +delete f.h +>delete f.h : boolean +>f.h : any +>f : Foo +>h : any + +delete f.i +>delete f.i : boolean +>f.i : never +>f : Foo +>i : never + +delete f.j +>delete f.j : boolean +>f.j : any +>f : Foo +>j : any + +delete a.a +>delete a.a : boolean +>a.a : number +>a : AA +>a : number + +delete a.b +>delete a.b : boolean +>a.b : number +>a : AA +>b : number + +delete b.a +>delete b.a : boolean +>b.a : number +>b : BB +>a : number + +delete b.b +>delete b.b : boolean +>b.b : number +>b : BB +>b : number + diff --git a/tests/cases/compiler/deleteExpressionMustBeOptional.ts b/tests/cases/compiler/deleteExpressionMustBeOptional.ts index 9f84d9ea2f1..98cdcabf807 100644 --- a/tests/cases/compiler/deleteExpressionMustBeOptional.ts +++ b/tests/cases/compiler/deleteExpressionMustBeOptional.ts @@ -1,42 +1,42 @@ -// @strict: true, false - -interface Foo { - a: number - b: number | undefined - c: number | null - d?: number - e: number | undefined | null - f?: number | undefined | null - g: unknown - h: any - i: never -} - -interface AA { - [s: string]: number -} - -type BB = { - [P in keyof any]: number -} - -declare const f: Foo -declare const a: AA -declare const b: BB - -delete f.a -delete f.b -delete f.c -delete f.d -delete f.e -delete f.f -delete f.g -delete f.h -delete f.i -delete f.j - -delete a.a -delete a.b - -delete b.a -delete b.b \ No newline at end of file +// @strict: true, false + +interface Foo { + a: number + b: number | undefined + c: number | null + d?: number + e: number | undefined | null + f?: number | undefined | null + g: unknown + h: any + i: never +} + +interface AA { + [s: string]: number +} + +type BB = { + [P in keyof any]: number +} + +declare const f: Foo +declare const a: AA +declare const b: BB + +delete f.a +delete f.b +delete f.c +delete f.d +delete f.e +delete f.f +delete f.g +delete f.h +delete f.i +delete f.j + +delete a.a +delete a.b + +delete b.a +delete b.b diff --git a/tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts b/tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts new file mode 100644 index 00000000000..03865521a13 --- /dev/null +++ b/tests/cases/compiler/deleteExpressionMustBeOptional_exactOptionalPropertyTypes.ts @@ -0,0 +1,43 @@ +// @strictNullChecks: true +// @exactOptionalPropertyTypes: true, false + +interface Foo { + a: number + b: number | undefined + c: number | null + d?: number + e: number | undefined | null + f?: number | undefined | null + g: unknown + h: any + i: never +} + +interface AA { + [s: string]: number +} + +type BB = { + [P in keyof any]: number +} + +declare const f: Foo +declare const a: AA +declare const b: BB + +delete f.a +delete f.b +delete f.c +delete f.d +delete f.e +delete f.f +delete f.g +delete f.h +delete f.i +delete f.j + +delete a.a +delete a.b + +delete b.a +delete b.b