diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0bf27e3f07b25..7cefe80e77eb7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27682,12 +27682,23 @@ namespace ts { } const links = getNodeLinks(expr); const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol); - if (symbol && isReadonlySymbol(symbol)) { - error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property); + if (symbol) { + if (isReadonlySymbol(symbol)) { + error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property); + } + + checkDeleteExpressionMustBeOptional(expr, getTypeOfSymbol(symbol)); } return booleanType; } + function checkDeleteExpressionMustBeOptional(expr: AccessExpression, type: Type) { + const AnyOrUnknownOrNeverFlags = TypeFlags.AnyOrUnknown | TypeFlags.Never; + if (strictNullChecks && !(type.flags & AnyOrUnknownOrNeverFlags) && !(getFalsyFlags(type) & TypeFlags.Undefined)) { + error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_optional); + } + } + function checkTypeOfExpression(node: TypeOfExpression): Type { checkExpression(node.expression); return typeofType; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1df368c4286ba..03f426084545b 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2963,6 +2963,10 @@ "category": "Error", "code": 2789 }, + "The operand of a 'delete' operator must be optional.": { + "category": "Error", + "code": 2790 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/controlFlowDeleteOperator.errors.txt b/tests/baselines/reference/controlFlowDeleteOperator.errors.txt index 91ec2aa0de8db..f5a6823a778b0 100644 --- a/tests/baselines/reference/controlFlowDeleteOperator.errors.txt +++ b/tests/baselines/reference/controlFlowDeleteOperator.errors.txt @@ -1,7 +1,8 @@ +tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts(10,12): error TS2790: The operand of a 'delete' operator must be optional. tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts(14,12): error TS2703: The operand of a 'delete' operator must be a property reference. -==== tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts (1 errors) ==== +==== tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts (2 errors) ==== function f() { let x: { a?: number | string, b: number | string } = { b: 1 }; x.a; @@ -12,6 +13,8 @@ tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts(14,12): error T x.b; delete x.a; delete x.b; + ~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. x.a; x.b; x; diff --git a/tests/baselines/reference/deleteChain.errors.txt b/tests/baselines/reference/deleteChain.errors.txt new file mode 100644 index 0000000000000..dd71641957338 --- /dev/null +++ b/tests/baselines/reference/deleteChain.errors.txt @@ -0,0 +1,66 @@ +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(2,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(3,9): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(6,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(7,9): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(10,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(11,9): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(14,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(15,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(16,9): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(19,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(20,9): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(23,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(24,9): error TS2790: The operand of a 'delete' operator must be optional. + + +==== tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts (13 errors) ==== + declare const o1: undefined | { b: string }; + delete o1?.b; + ~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete (o1?.b); + ~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + + declare const o2: undefined | { b: { c: string } }; + delete o2?.b.c; + ~~~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete (o2?.b.c); + ~~~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + + declare const o3: { b: undefined | { c: string } }; + delete o3.b?.c; + ~~~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete (o3.b?.c); + ~~~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + + declare const o4: { b?: { c: { d?: { e: string } } } }; + delete o4.b?.c.d?.e; + ~~~~~~~~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete (o4.b?.c.d)?.e; + ~~~~~~~~~~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete (o4.b?.c.d?.e); + ~~~~~~~~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + + declare const o5: { b?(): { c: { d?: { e: string } } } }; + delete o5.b?.().c.d?.e; + ~~~~~~~~~~~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete (o5.b?.().c.d?.e); + ~~~~~~~~~~~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + + declare const o6: { b?: { c: { d?: { e: string } } } }; + delete o6.b?.['c'].d?.['e']; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + delete (o6.b?.['c'].d?.['e']); + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. \ No newline at end of file diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).errors.txt b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).errors.txt new file mode 100644 index 0000000000000..8a876cb63502f --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).errors.txt @@ -0,0 +1,46 @@ +tests/cases/compiler/deleteExpressionMustBeOptional.ts(34,10): error TS2339: Property 'j' does not exist on type 'Foo'. + + +==== tests/cases/compiler/deleteExpressionMustBeOptional.ts (1 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 + 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 + ~ +!!! 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(strict=false).js b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).js new file mode 100644 index 0000000000000..268c76175bff1 --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).js @@ -0,0 +1,57 @@ +//// [deleteExpressionMustBeOptional.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.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(strict=false).symbols b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).symbols new file mode 100644 index 0000000000000..aad7423a133ad --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).symbols @@ -0,0 +1,118 @@ +=== tests/cases/compiler/deleteExpressionMustBeOptional.ts === +interface Foo { +>Foo : Symbol(Foo, Decl(deleteExpressionMustBeOptional.ts, 0, 0)) + + a: number +>a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional.ts, 0, 15)) + + b: number | undefined +>b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional.ts, 1, 13)) + + c: number | null +>c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional.ts, 2, 25)) + + d?: number +>d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional.ts, 3, 20)) + + e: number | undefined | null +>e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional.ts, 4, 14)) + + f?: number | undefined | null +>f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional.ts, 5, 32)) + + g: unknown +>g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional.ts, 6, 33)) + + h: any +>h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional.ts, 7, 14)) + + i: never +>i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional.ts, 8, 10)) +} + +interface AA { +>AA : Symbol(AA, Decl(deleteExpressionMustBeOptional.ts, 10, 1)) + + [s: string]: number +>s : Symbol(s, Decl(deleteExpressionMustBeOptional.ts, 13, 5)) +} + +type BB = { +>BB : Symbol(BB, Decl(deleteExpressionMustBeOptional.ts, 14, 1)) + + [P in keyof any]: number +>P : Symbol(P, Decl(deleteExpressionMustBeOptional.ts, 17, 5)) +} + +declare const f: Foo +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>Foo : Symbol(Foo, Decl(deleteExpressionMustBeOptional.ts, 0, 0)) + +declare const a: AA +>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13)) +>AA : Symbol(AA, Decl(deleteExpressionMustBeOptional.ts, 10, 1)) + +declare const b: BB +>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13)) +>BB : Symbol(BB, Decl(deleteExpressionMustBeOptional.ts, 14, 1)) + +delete f.a +>f.a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional.ts, 0, 15)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional.ts, 0, 15)) + +delete f.b +>f.b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional.ts, 1, 13)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional.ts, 1, 13)) + +delete f.c +>f.c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional.ts, 2, 25)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional.ts, 2, 25)) + +delete f.d +>f.d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional.ts, 3, 20)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional.ts, 3, 20)) + +delete f.e +>f.e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional.ts, 4, 14)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional.ts, 4, 14)) + +delete f.f +>f.f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional.ts, 5, 32)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional.ts, 5, 32)) + +delete f.g +>f.g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional.ts, 6, 33)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional.ts, 6, 33)) + +delete f.h +>f.h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional.ts, 7, 14)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional.ts, 7, 14)) + +delete f.i +>f.i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional.ts, 8, 10)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional.ts, 8, 10)) + +delete f.j +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) + +delete a.a +>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13)) + +delete a.b +>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13)) + +delete b.a +>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13)) + +delete b.b +>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13)) + diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).types b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).types new file mode 100644 index 0000000000000..371bb25e96d82 --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=false).types @@ -0,0 +1,137 @@ +=== tests/cases/compiler/deleteExpressionMustBeOptional.ts === +interface Foo { + a: number +>a : number + + b: number | undefined +>b : number + + c: number | null +>c : number +>null : null + + d?: number +>d : number + + e: number | undefined | null +>e : number +>null : null + + f?: number | undefined | null +>f : number +>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 +>f : Foo +>b : number + +delete f.c +>delete f.c : boolean +>f.c : number +>f : Foo +>c : number + +delete f.d +>delete f.d : boolean +>f.d : number +>f : Foo +>d : number + +delete f.e +>delete f.e : boolean +>f.e : number +>f : Foo +>e : number + +delete f.f +>delete f.f : boolean +>f.f : number +>f : Foo +>f : number + +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(strict=true).errors.txt b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).errors.txt new file mode 100644 index 0000000000000..b1cabc960096f --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).errors.txt @@ -0,0 +1,52 @@ +tests/cases/compiler/deleteExpressionMustBeOptional.ts(25,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/compiler/deleteExpressionMustBeOptional.ts(27,8): error TS2790: The operand of a 'delete' operator must be optional. +tests/cases/compiler/deleteExpressionMustBeOptional.ts(34,10): error TS2339: Property 'j' does not exist on type 'Foo'. + + +==== tests/cases/compiler/deleteExpressionMustBeOptional.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(strict=true).js b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).js new file mode 100644 index 0000000000000..ca81456b4f43b --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).js @@ -0,0 +1,58 @@ +//// [deleteExpressionMustBeOptional.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.js] +"use strict"; +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(strict=true).symbols b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).symbols new file mode 100644 index 0000000000000..aad7423a133ad --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).symbols @@ -0,0 +1,118 @@ +=== tests/cases/compiler/deleteExpressionMustBeOptional.ts === +interface Foo { +>Foo : Symbol(Foo, Decl(deleteExpressionMustBeOptional.ts, 0, 0)) + + a: number +>a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional.ts, 0, 15)) + + b: number | undefined +>b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional.ts, 1, 13)) + + c: number | null +>c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional.ts, 2, 25)) + + d?: number +>d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional.ts, 3, 20)) + + e: number | undefined | null +>e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional.ts, 4, 14)) + + f?: number | undefined | null +>f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional.ts, 5, 32)) + + g: unknown +>g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional.ts, 6, 33)) + + h: any +>h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional.ts, 7, 14)) + + i: never +>i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional.ts, 8, 10)) +} + +interface AA { +>AA : Symbol(AA, Decl(deleteExpressionMustBeOptional.ts, 10, 1)) + + [s: string]: number +>s : Symbol(s, Decl(deleteExpressionMustBeOptional.ts, 13, 5)) +} + +type BB = { +>BB : Symbol(BB, Decl(deleteExpressionMustBeOptional.ts, 14, 1)) + + [P in keyof any]: number +>P : Symbol(P, Decl(deleteExpressionMustBeOptional.ts, 17, 5)) +} + +declare const f: Foo +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>Foo : Symbol(Foo, Decl(deleteExpressionMustBeOptional.ts, 0, 0)) + +declare const a: AA +>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13)) +>AA : Symbol(AA, Decl(deleteExpressionMustBeOptional.ts, 10, 1)) + +declare const b: BB +>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13)) +>BB : Symbol(BB, Decl(deleteExpressionMustBeOptional.ts, 14, 1)) + +delete f.a +>f.a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional.ts, 0, 15)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional.ts, 0, 15)) + +delete f.b +>f.b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional.ts, 1, 13)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional.ts, 1, 13)) + +delete f.c +>f.c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional.ts, 2, 25)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional.ts, 2, 25)) + +delete f.d +>f.d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional.ts, 3, 20)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional.ts, 3, 20)) + +delete f.e +>f.e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional.ts, 4, 14)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional.ts, 4, 14)) + +delete f.f +>f.f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional.ts, 5, 32)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional.ts, 5, 32)) + +delete f.g +>f.g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional.ts, 6, 33)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional.ts, 6, 33)) + +delete f.h +>f.h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional.ts, 7, 14)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional.ts, 7, 14)) + +delete f.i +>f.i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional.ts, 8, 10)) +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) +>i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional.ts, 8, 10)) + +delete f.j +>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13)) + +delete a.a +>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13)) + +delete a.b +>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13)) + +delete b.a +>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13)) + +delete b.b +>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13)) + diff --git a/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).types b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).types new file mode 100644 index 0000000000000..a3d6f52b7c436 --- /dev/null +++ b/tests/baselines/reference/deleteExpressionMustBeOptional(strict=true).types @@ -0,0 +1,137 @@ +=== tests/cases/compiler/deleteExpressionMustBeOptional.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/privateNamesNoDelete.errors.txt b/tests/baselines/reference/privateNamesNoDelete.errors.txt index d593fe107a181..e2fc11cb4ac73 100644 --- a/tests/baselines/reference/privateNamesNoDelete.errors.txt +++ b/tests/baselines/reference/privateNamesNoDelete.errors.txt @@ -1,12 +1,15 @@ +tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts(4,16): error TS2790: The operand of a 'delete' operator must be optional. tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts(4,16): error TS18011: The operand of a 'delete' operator cannot be a private identifier. -==== tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts (1 errors) ==== +==== tests/cases/conformance/classes/members/privateNames/privateNamesNoDelete.ts (2 errors) ==== class A { #v = 1; constructor() { delete this.#v; // Error: The operand of a delete operator cannot be a private name. ~~~~~~~ +!!! error TS2790: The operand of a 'delete' operator must be optional. + ~~~~~~~ !!! error TS18011: The operand of a 'delete' operator cannot be a private identifier. } } diff --git a/tests/cases/compiler/deleteExpressionMustBeOptional.ts b/tests/cases/compiler/deleteExpressionMustBeOptional.ts new file mode 100644 index 0000000000000..9f84d9ea2f1e5 --- /dev/null +++ b/tests/cases/compiler/deleteExpressionMustBeOptional.ts @@ -0,0 +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