fix emit for delete on optional chain (#35090)

* fix emit for delete on optional chain

* Apply suggestions from code review

Co-Authored-By: Ron Buckton <ron.buckton@microsoft.com>
This commit is contained in:
Klaus Meinhardt
2019-11-19 01:34:47 +01:00
committed by Ron Buckton
parent 8b83703632
commit fce728e07f
5 changed files with 406 additions and 16 deletions

View File

@@ -24,7 +24,7 @@ namespace ts {
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.CallExpression:
if (node.flags & NodeFlags.OptionalChain) {
const updated = visitOptionalExpression(node as OptionalChain, /*captureThisArg*/ false);
const updated = visitOptionalExpression(node as OptionalChain, /*captureThisArg*/ false, /*isDelete*/ false);
Debug.assertNotNode(updated, isSyntheticReference);
return updated;
}
@@ -34,6 +34,8 @@ namespace ts {
return transformNullishCoalescingExpression(<BinaryExpression>node);
}
return visitEachChild(node, visitor, context);
case SyntaxKind.DeleteExpression:
return visitDeleteExpression(node as DeleteExpression);
default:
return visitEachChild(node, visitor, context);
}
@@ -48,8 +50,8 @@ namespace ts {
return { expression: chain.expression, chain: links };
}
function visitNonOptionalParenthesizedExpression(node: ParenthesizedExpression, captureThisArg: boolean): Expression {
const expression = visitNonOptionalExpression(node.expression, captureThisArg);
function visitNonOptionalParenthesizedExpression(node: ParenthesizedExpression, captureThisArg: boolean, isDelete: boolean): Expression {
const expression = visitNonOptionalExpression(node.expression, captureThisArg, isDelete);
if (isSyntheticReference(expression)) {
// `(a.b)` -> { expression `((_a = a).b)`, thisArg: `_a` }
// `(a[b])` -> { expression `((_a = a)[b])`, thisArg: `_a` }
@@ -58,10 +60,10 @@ namespace ts {
return updateParen(node, expression);
}
function visitNonOptionalPropertyOrElementAccessExpression(node: AccessExpression, captureThisArg: boolean): Expression {
function visitNonOptionalPropertyOrElementAccessExpression(node: AccessExpression, captureThisArg: boolean, isDelete: boolean): Expression {
if (isOptionalChain(node)) {
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
return visitOptionalExpression(node, captureThisArg);
return visitOptionalExpression(node, captureThisArg, isDelete);
}
let expression: Expression = visitNode(node.expression, visitor, isExpression);
@@ -87,24 +89,24 @@ namespace ts {
function visitNonOptionalCallExpression(node: CallExpression, captureThisArg: boolean): Expression {
if (isOptionalChain(node)) {
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
return visitOptionalExpression(node, captureThisArg);
return visitOptionalExpression(node, captureThisArg, /*isDelete*/ false);
}
return visitEachChild(node, visitor, context);
}
function visitNonOptionalExpression(node: Expression, captureThisArg: boolean): Expression {
function visitNonOptionalExpression(node: Expression, captureThisArg: boolean, isDelete: boolean): Expression {
switch (node.kind) {
case SyntaxKind.ParenthesizedExpression: return visitNonOptionalParenthesizedExpression(node as ParenthesizedExpression, captureThisArg);
case SyntaxKind.ParenthesizedExpression: return visitNonOptionalParenthesizedExpression(node as ParenthesizedExpression, captureThisArg, isDelete);
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression: return visitNonOptionalPropertyOrElementAccessExpression(node as AccessExpression, captureThisArg);
case SyntaxKind.ElementAccessExpression: return visitNonOptionalPropertyOrElementAccessExpression(node as AccessExpression, captureThisArg, isDelete);
case SyntaxKind.CallExpression: return visitNonOptionalCallExpression(node as CallExpression, captureThisArg);
default: return visitNode(node, visitor, isExpression);
}
}
function visitOptionalExpression(node: OptionalChain, captureThisArg: boolean): Expression {
function visitOptionalExpression(node: OptionalChain, captureThisArg: boolean, isDelete: boolean): Expression {
const { expression, chain } = flattenChain(node);
const left = visitNonOptionalExpression(expression, isCallChain(chain[0]));
const left = visitNonOptionalExpression(expression, isCallChain(chain[0]), /*isDelete*/ false);
const leftThisArg = isSyntheticReference(left) ? left.thisArg : undefined;
let leftExpression = isSyntheticReference(left) ? left.expression : left;
let capturedLeft: Expression = leftExpression;
@@ -152,11 +154,9 @@ namespace ts {
setOriginalNode(rightExpression, segment);
}
const target = createConditional(
createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true),
createVoidZero(),
rightExpression,
);
const target = isDelete
? createConditional(createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), createTrue(), createDelete(rightExpression))
: createConditional(createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), createVoidZero(), rightExpression);
return thisArg ? createSyntheticReferenceExpression(target, thisArg) : target;
}
@@ -197,5 +197,11 @@ namespace ts {
expression.kind !== SyntaxKind.ThisKeyword &&
expression.kind !== SyntaxKind.SuperKeyword;
}
function visitDeleteExpression(node: DeleteExpression) {
return isOptionalChain(skipParentheses(node.expression))
? setOriginalNode(visitNonOptionalExpression(node.expression, /*captureThisArg*/ false, /*isDelete*/ true), node)
: updateDelete(node, visitNode(node.expression, visitor, isExpression));
}
}
}

View File

@@ -0,0 +1,42 @@
//// [deleteChain.ts]
declare const o1: undefined | { b: string };
delete o1?.b;
delete (o1?.b);
declare const o2: undefined | { b: { c: string } };
delete o2?.b.c;
delete (o2?.b.c);
declare const o3: { b: undefined | { c: string } };
delete o3.b?.c;
delete (o3.b?.c);
declare const o4: { b?: { c: { d?: { e: string } } } };
delete o4.b?.c.d?.e;
delete (o4.b?.c.d)?.e;
delete (o4.b?.c.d?.e);
declare const o5: { b?(): { c: { d?: { e: string } } } };
delete o5.b?.().c.d?.e;
delete (o5.b?.().c.d?.e);
declare const o6: { b?: { c: { d?: { e: string } } } };
delete o6.b?.['c'].d?.['e'];
delete (o6.b?.['c'].d?.['e']);
//// [deleteChain.js]
"use strict";
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
o1 === null || o1 === void 0 ? true : delete o1.b;
(o1 === null || o1 === void 0 ? true : delete o1.b);
o2 === null || o2 === void 0 ? true : delete o2.b.c;
(o2 === null || o2 === void 0 ? true : delete o2.b.c);
(_a = o3.b) === null || _a === void 0 ? true : delete _a.c;
((_b = o3.b) === null || _b === void 0 ? true : delete _b.c);
(_d = (_c = o4.b) === null || _c === void 0 ? void 0 : _c.c.d) === null || _d === void 0 ? true : delete _d.e;
(_f = ((_e = o4.b) === null || _e === void 0 ? void 0 : _e.c.d)) === null || _f === void 0 ? true : delete _f.e;
((_h = (_g = o4.b) === null || _g === void 0 ? void 0 : _g.c.d) === null || _h === void 0 ? true : delete _h.e);
(_k = (_j = o5.b) === null || _j === void 0 ? void 0 : _j.call(o5).c.d) === null || _k === void 0 ? true : delete _k.e;
((_m = (_l = o5.b) === null || _l === void 0 ? void 0 : _l.call(o5).c.d) === null || _m === void 0 ? true : delete _m.e);
(_p = (_o = o6.b) === null || _o === void 0 ? void 0 : _o['c'].d) === null || _p === void 0 ? true : delete _p['e'];
((_r = (_q = o6.b) === null || _q === void 0 ? void 0 : _q['c'].d) === null || _r === void 0 ? true : delete _r['e']);

View File

@@ -0,0 +1,143 @@
=== tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts ===
declare const o1: undefined | { b: string };
>o1 : Symbol(o1, Decl(deleteChain.ts, 0, 13))
>b : Symbol(b, Decl(deleteChain.ts, 0, 31))
delete o1?.b;
>o1?.b : Symbol(b, Decl(deleteChain.ts, 0, 31))
>o1 : Symbol(o1, Decl(deleteChain.ts, 0, 13))
>b : Symbol(b, Decl(deleteChain.ts, 0, 31))
delete (o1?.b);
>o1?.b : Symbol(b, Decl(deleteChain.ts, 0, 31))
>o1 : Symbol(o1, Decl(deleteChain.ts, 0, 13))
>b : Symbol(b, Decl(deleteChain.ts, 0, 31))
declare const o2: undefined | { b: { c: string } };
>o2 : Symbol(o2, Decl(deleteChain.ts, 4, 13))
>b : Symbol(b, Decl(deleteChain.ts, 4, 31))
>c : Symbol(c, Decl(deleteChain.ts, 4, 36))
delete o2?.b.c;
>o2?.b.c : Symbol(c, Decl(deleteChain.ts, 4, 36))
>o2?.b : Symbol(b, Decl(deleteChain.ts, 4, 31))
>o2 : Symbol(o2, Decl(deleteChain.ts, 4, 13))
>b : Symbol(b, Decl(deleteChain.ts, 4, 31))
>c : Symbol(c, Decl(deleteChain.ts, 4, 36))
delete (o2?.b.c);
>o2?.b.c : Symbol(c, Decl(deleteChain.ts, 4, 36))
>o2?.b : Symbol(b, Decl(deleteChain.ts, 4, 31))
>o2 : Symbol(o2, Decl(deleteChain.ts, 4, 13))
>b : Symbol(b, Decl(deleteChain.ts, 4, 31))
>c : Symbol(c, Decl(deleteChain.ts, 4, 36))
declare const o3: { b: undefined | { c: string } };
>o3 : Symbol(o3, Decl(deleteChain.ts, 8, 13))
>b : Symbol(b, Decl(deleteChain.ts, 8, 19))
>c : Symbol(c, Decl(deleteChain.ts, 8, 36))
delete o3.b?.c;
>o3.b?.c : Symbol(c, Decl(deleteChain.ts, 8, 36))
>o3.b : Symbol(b, Decl(deleteChain.ts, 8, 19))
>o3 : Symbol(o3, Decl(deleteChain.ts, 8, 13))
>b : Symbol(b, Decl(deleteChain.ts, 8, 19))
>c : Symbol(c, Decl(deleteChain.ts, 8, 36))
delete (o3.b?.c);
>o3.b?.c : Symbol(c, Decl(deleteChain.ts, 8, 36))
>o3.b : Symbol(b, Decl(deleteChain.ts, 8, 19))
>o3 : Symbol(o3, Decl(deleteChain.ts, 8, 13))
>b : Symbol(b, Decl(deleteChain.ts, 8, 19))
>c : Symbol(c, Decl(deleteChain.ts, 8, 36))
declare const o4: { b?: { c: { d?: { e: string } } } };
>o4 : Symbol(o4, Decl(deleteChain.ts, 12, 13))
>b : Symbol(b, Decl(deleteChain.ts, 12, 19))
>c : Symbol(c, Decl(deleteChain.ts, 12, 25))
>d : Symbol(d, Decl(deleteChain.ts, 12, 30))
>e : Symbol(e, Decl(deleteChain.ts, 12, 36))
delete o4.b?.c.d?.e;
>o4.b?.c.d?.e : Symbol(e, Decl(deleteChain.ts, 12, 36))
>o4.b?.c.d : Symbol(d, Decl(deleteChain.ts, 12, 30))
>o4.b?.c : Symbol(c, Decl(deleteChain.ts, 12, 25))
>o4.b : Symbol(b, Decl(deleteChain.ts, 12, 19))
>o4 : Symbol(o4, Decl(deleteChain.ts, 12, 13))
>b : Symbol(b, Decl(deleteChain.ts, 12, 19))
>c : Symbol(c, Decl(deleteChain.ts, 12, 25))
>d : Symbol(d, Decl(deleteChain.ts, 12, 30))
>e : Symbol(e, Decl(deleteChain.ts, 12, 36))
delete (o4.b?.c.d)?.e;
>(o4.b?.c.d)?.e : Symbol(e, Decl(deleteChain.ts, 12, 36))
>o4.b?.c.d : Symbol(d, Decl(deleteChain.ts, 12, 30))
>o4.b?.c : Symbol(c, Decl(deleteChain.ts, 12, 25))
>o4.b : Symbol(b, Decl(deleteChain.ts, 12, 19))
>o4 : Symbol(o4, Decl(deleteChain.ts, 12, 13))
>b : Symbol(b, Decl(deleteChain.ts, 12, 19))
>c : Symbol(c, Decl(deleteChain.ts, 12, 25))
>d : Symbol(d, Decl(deleteChain.ts, 12, 30))
>e : Symbol(e, Decl(deleteChain.ts, 12, 36))
delete (o4.b?.c.d?.e);
>o4.b?.c.d?.e : Symbol(e, Decl(deleteChain.ts, 12, 36))
>o4.b?.c.d : Symbol(d, Decl(deleteChain.ts, 12, 30))
>o4.b?.c : Symbol(c, Decl(deleteChain.ts, 12, 25))
>o4.b : Symbol(b, Decl(deleteChain.ts, 12, 19))
>o4 : Symbol(o4, Decl(deleteChain.ts, 12, 13))
>b : Symbol(b, Decl(deleteChain.ts, 12, 19))
>c : Symbol(c, Decl(deleteChain.ts, 12, 25))
>d : Symbol(d, Decl(deleteChain.ts, 12, 30))
>e : Symbol(e, Decl(deleteChain.ts, 12, 36))
declare const o5: { b?(): { c: { d?: { e: string } } } };
>o5 : Symbol(o5, Decl(deleteChain.ts, 17, 13))
>b : Symbol(b, Decl(deleteChain.ts, 17, 19))
>c : Symbol(c, Decl(deleteChain.ts, 17, 27))
>d : Symbol(d, Decl(deleteChain.ts, 17, 32))
>e : Symbol(e, Decl(deleteChain.ts, 17, 38))
delete o5.b?.().c.d?.e;
>o5.b?.().c.d?.e : Symbol(e, Decl(deleteChain.ts, 17, 38))
>o5.b?.().c.d : Symbol(d, Decl(deleteChain.ts, 17, 32))
>o5.b?.().c : Symbol(c, Decl(deleteChain.ts, 17, 27))
>o5.b : Symbol(b, Decl(deleteChain.ts, 17, 19))
>o5 : Symbol(o5, Decl(deleteChain.ts, 17, 13))
>b : Symbol(b, Decl(deleteChain.ts, 17, 19))
>c : Symbol(c, Decl(deleteChain.ts, 17, 27))
>d : Symbol(d, Decl(deleteChain.ts, 17, 32))
>e : Symbol(e, Decl(deleteChain.ts, 17, 38))
delete (o5.b?.().c.d?.e);
>o5.b?.().c.d?.e : Symbol(e, Decl(deleteChain.ts, 17, 38))
>o5.b?.().c.d : Symbol(d, Decl(deleteChain.ts, 17, 32))
>o5.b?.().c : Symbol(c, Decl(deleteChain.ts, 17, 27))
>o5.b : Symbol(b, Decl(deleteChain.ts, 17, 19))
>o5 : Symbol(o5, Decl(deleteChain.ts, 17, 13))
>b : Symbol(b, Decl(deleteChain.ts, 17, 19))
>c : Symbol(c, Decl(deleteChain.ts, 17, 27))
>d : Symbol(d, Decl(deleteChain.ts, 17, 32))
>e : Symbol(e, Decl(deleteChain.ts, 17, 38))
declare const o6: { b?: { c: { d?: { e: string } } } };
>o6 : Symbol(o6, Decl(deleteChain.ts, 21, 13))
>b : Symbol(b, Decl(deleteChain.ts, 21, 19))
>c : Symbol(c, Decl(deleteChain.ts, 21, 25))
>d : Symbol(d, Decl(deleteChain.ts, 21, 30))
>e : Symbol(e, Decl(deleteChain.ts, 21, 36))
delete o6.b?.['c'].d?.['e'];
>o6.b?.['c'].d : Symbol(d, Decl(deleteChain.ts, 21, 30))
>o6.b : Symbol(b, Decl(deleteChain.ts, 21, 19))
>o6 : Symbol(o6, Decl(deleteChain.ts, 21, 13))
>b : Symbol(b, Decl(deleteChain.ts, 21, 19))
>d : Symbol(d, Decl(deleteChain.ts, 21, 30))
delete (o6.b?.['c'].d?.['e']);
>o6.b?.['c'].d : Symbol(d, Decl(deleteChain.ts, 21, 30))
>o6.b : Symbol(b, Decl(deleteChain.ts, 21, 19))
>o6 : Symbol(o6, Decl(deleteChain.ts, 21, 13))
>b : Symbol(b, Decl(deleteChain.ts, 21, 19))
>d : Symbol(d, Decl(deleteChain.ts, 21, 30))

View File

@@ -0,0 +1,173 @@
=== tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts ===
declare const o1: undefined | { b: string };
>o1 : { b: string; } | undefined
>b : string
delete o1?.b;
>delete o1?.b : boolean
>o1?.b : string | undefined
>o1 : { b: string; } | undefined
>b : string | undefined
delete (o1?.b);
>delete (o1?.b) : boolean
>(o1?.b) : string | undefined
>o1?.b : string | undefined
>o1 : { b: string; } | undefined
>b : string | undefined
declare const o2: undefined | { b: { c: string } };
>o2 : { b: { c: string; }; } | undefined
>b : { c: string; }
>c : string
delete o2?.b.c;
>delete o2?.b.c : boolean
>o2?.b.c : string | undefined
>o2?.b : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>b : { c: string; } | undefined
>c : string | undefined
delete (o2?.b.c);
>delete (o2?.b.c) : boolean
>(o2?.b.c) : string | undefined
>o2?.b.c : string | undefined
>o2?.b : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>b : { c: string; } | undefined
>c : string | undefined
declare const o3: { b: undefined | { c: string } };
>o3 : { b: { c: string; } | undefined; }
>b : { c: string; } | undefined
>c : string
delete o3.b?.c;
>delete o3.b?.c : boolean
>o3.b?.c : string | undefined
>o3.b : { c: string; } | undefined
>o3 : { b: { c: string; } | undefined; }
>b : { c: string; } | undefined
>c : string | undefined
delete (o3.b?.c);
>delete (o3.b?.c) : boolean
>(o3.b?.c) : string | undefined
>o3.b?.c : string | undefined
>o3.b : { c: string; } | undefined
>o3 : { b: { c: string; } | undefined; }
>b : { c: string; } | undefined
>c : string | undefined
declare const o4: { b?: { c: { d?: { e: string } } } };
>o4 : { b?: { c: { d?: { e: string; } | undefined; }; } | undefined; }
>b : { c: { d?: { e: string; } | undefined; }; } | undefined
>c : { d?: { e: string; } | undefined; }
>d : { e: string; } | undefined
>e : string
delete o4.b?.c.d?.e;
>delete o4.b?.c.d?.e : boolean
>o4.b?.c.d?.e : string | undefined
>o4.b?.c.d : { e: string; } | undefined
>o4.b?.c : { d?: { e: string; } | undefined; } | undefined
>o4.b : { c: { d?: { e: string; } | undefined; }; } | undefined
>o4 : { b?: { c: { d?: { e: string; } | undefined; }; } | undefined; }
>b : { c: { d?: { e: string; } | undefined; }; } | undefined
>c : { d?: { e: string; } | undefined; } | undefined
>d : { e: string; } | undefined
>e : string | undefined
delete (o4.b?.c.d)?.e;
>delete (o4.b?.c.d)?.e : boolean
>(o4.b?.c.d)?.e : string | undefined
>(o4.b?.c.d) : { e: string; } | undefined
>o4.b?.c.d : { e: string; } | undefined
>o4.b?.c : { d?: { e: string; } | undefined; } | undefined
>o4.b : { c: { d?: { e: string; } | undefined; }; } | undefined
>o4 : { b?: { c: { d?: { e: string; } | undefined; }; } | undefined; }
>b : { c: { d?: { e: string; } | undefined; }; } | undefined
>c : { d?: { e: string; } | undefined; } | undefined
>d : { e: string; } | undefined
>e : string | undefined
delete (o4.b?.c.d?.e);
>delete (o4.b?.c.d?.e) : boolean
>(o4.b?.c.d?.e) : string | undefined
>o4.b?.c.d?.e : string | undefined
>o4.b?.c.d : { e: string; } | undefined
>o4.b?.c : { d?: { e: string; } | undefined; } | undefined
>o4.b : { c: { d?: { e: string; } | undefined; }; } | undefined
>o4 : { b?: { c: { d?: { e: string; } | undefined; }; } | undefined; }
>b : { c: { d?: { e: string; } | undefined; }; } | undefined
>c : { d?: { e: string; } | undefined; } | undefined
>d : { e: string; } | undefined
>e : string | undefined
declare const o5: { b?(): { c: { d?: { e: string } } } };
>o5 : { b?(): { c: { d?: { e: string; } | undefined; }; }; }
>b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>c : { d?: { e: string; } | undefined; }
>d : { e: string; } | undefined
>e : string
delete o5.b?.().c.d?.e;
>delete o5.b?.().c.d?.e : boolean
>o5.b?.().c.d?.e : string | undefined
>o5.b?.().c.d : { e: string; } | undefined
>o5.b?.().c : { d?: { e: string; } | undefined; } | undefined
>o5.b?.() : { c: { d?: { e: string; } | undefined; }; } | undefined
>o5.b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>o5 : { b?(): { c: { d?: { e: string; } | undefined; }; }; }
>b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>c : { d?: { e: string; } | undefined; } | undefined
>d : { e: string; } | undefined
>e : string | undefined
delete (o5.b?.().c.d?.e);
>delete (o5.b?.().c.d?.e) : boolean
>(o5.b?.().c.d?.e) : string | undefined
>o5.b?.().c.d?.e : string | undefined
>o5.b?.().c.d : { e: string; } | undefined
>o5.b?.().c : { d?: { e: string; } | undefined; } | undefined
>o5.b?.() : { c: { d?: { e: string; } | undefined; }; } | undefined
>o5.b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>o5 : { b?(): { c: { d?: { e: string; } | undefined; }; }; }
>b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>c : { d?: { e: string; } | undefined; } | undefined
>d : { e: string; } | undefined
>e : string | undefined
declare const o6: { b?: { c: { d?: { e: string } } } };
>o6 : { b?: { c: { d?: { e: string; } | undefined; }; } | undefined; }
>b : { c: { d?: { e: string; } | undefined; }; } | undefined
>c : { d?: { e: string; } | undefined; }
>d : { e: string; } | undefined
>e : string
delete o6.b?.['c'].d?.['e'];
>delete o6.b?.['c'].d?.['e'] : boolean
>o6.b?.['c'].d?.['e'] : string | undefined
>o6.b?.['c'].d : { e: string; } | undefined
>o6.b?.['c'] : { d?: { e: string; } | undefined; } | undefined
>o6.b : { c: { d?: { e: string; } | undefined; }; } | undefined
>o6 : { b?: { c: { d?: { e: string; } | undefined; }; } | undefined; }
>b : { c: { d?: { e: string; } | undefined; }; } | undefined
>'c' : "c"
>d : { e: string; } | undefined
>'e' : "e"
delete (o6.b?.['c'].d?.['e']);
>delete (o6.b?.['c'].d?.['e']) : boolean
>(o6.b?.['c'].d?.['e']) : string | undefined
>o6.b?.['c'].d?.['e'] : string | undefined
>o6.b?.['c'].d : { e: string; } | undefined
>o6.b?.['c'] : { d?: { e: string; } | undefined; } | undefined
>o6.b : { c: { d?: { e: string; } | undefined; }; } | undefined
>o6 : { b?: { c: { d?: { e: string; } | undefined; }; } | undefined; }
>b : { c: { d?: { e: string; } | undefined; }; } | undefined
>'c' : "c"
>d : { e: string; } | undefined
>'e' : "e"

View File

@@ -0,0 +1,26 @@
// @strict: true
declare const o1: undefined | { b: string };
delete o1?.b;
delete (o1?.b);
declare const o2: undefined | { b: { c: string } };
delete o2?.b.c;
delete (o2?.b.c);
declare const o3: { b: undefined | { c: string } };
delete o3.b?.c;
delete (o3.b?.c);
declare const o4: { b?: { c: { d?: { e: string } } } };
delete o4.b?.c.d?.e;
delete (o4.b?.c.d)?.e;
delete (o4.b?.c.d?.e);
declare const o5: { b?(): { c: { d?: { e: string } } } };
delete o5.b?.().c.d?.e;
delete (o5.b?.().c.d?.e);
declare const o6: { b?: { c: { d?: { e: string } } } };
delete o6.b?.['c'].d?.['e'];
delete (o6.b?.['c'].d?.['e']);