mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Add rule to auto-paren optional chain in normal prop or element access (#50156)
This commit is contained in:
@@ -1188,7 +1188,7 @@ namespace ts {
|
||||
// @api
|
||||
function createDecorator(expression: Expression) {
|
||||
const node = createBaseNode<Decorator>(SyntaxKind.Decorator);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false);
|
||||
node.transformFlags |=
|
||||
propagateChildFlags(node.expression) |
|
||||
TransformFlags.ContainsTypeScript |
|
||||
@@ -2325,7 +2325,7 @@ namespace ts {
|
||||
// @api
|
||||
function createPropertyAccessExpression(expression: Expression, name: string | Identifier | PrivateIdentifier) {
|
||||
const node = createBaseExpression<PropertyAccessExpression>(SyntaxKind.PropertyAccessExpression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false);
|
||||
node.name = asName(name);
|
||||
node.transformFlags =
|
||||
propagateChildFlags(node.expression) |
|
||||
@@ -2357,7 +2357,7 @@ namespace ts {
|
||||
function createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier) {
|
||||
const node = createBaseExpression<PropertyAccessChain>(SyntaxKind.PropertyAccessExpression);
|
||||
node.flags |= NodeFlags.OptionalChain;
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ true);
|
||||
node.questionDotToken = questionDotToken;
|
||||
node.name = asName(name);
|
||||
node.transformFlags |=
|
||||
@@ -2385,7 +2385,7 @@ namespace ts {
|
||||
// @api
|
||||
function createElementAccessExpression(expression: Expression, index: number | Expression) {
|
||||
const node = createBaseExpression<ElementAccessExpression>(SyntaxKind.ElementAccessExpression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false);
|
||||
node.argumentExpression = asExpression(index);
|
||||
node.transformFlags |=
|
||||
propagateChildFlags(node.expression) |
|
||||
@@ -2415,7 +2415,7 @@ namespace ts {
|
||||
function createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression) {
|
||||
const node = createBaseExpression<ElementAccessChain>(SyntaxKind.ElementAccessExpression);
|
||||
node.flags |= NodeFlags.OptionalChain;
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ true);
|
||||
node.questionDotToken = questionDotToken;
|
||||
node.argumentExpression = asExpression(index);
|
||||
node.transformFlags |=
|
||||
@@ -2441,7 +2441,7 @@ namespace ts {
|
||||
// @api
|
||||
function createCallExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
|
||||
const node = createBaseExpression<CallExpression>(SyntaxKind.CallExpression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false);
|
||||
node.typeArguments = asNodeArray(typeArguments);
|
||||
node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray));
|
||||
node.transformFlags |=
|
||||
@@ -2476,7 +2476,7 @@ namespace ts {
|
||||
function createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
|
||||
const node = createBaseExpression<CallChain>(SyntaxKind.CallExpression);
|
||||
node.flags |= NodeFlags.OptionalChain;
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ true);
|
||||
node.questionDotToken = questionDotToken;
|
||||
node.typeArguments = asNodeArray(typeArguments);
|
||||
node.arguments = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray));
|
||||
@@ -2535,7 +2535,7 @@ namespace ts {
|
||||
// @api
|
||||
function createTaggedTemplateExpression(tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral) {
|
||||
const node = createBaseExpression<TaggedTemplateExpression>(SyntaxKind.TaggedTemplateExpression);
|
||||
node.tag = parenthesizerRules().parenthesizeLeftSideOfAccess(tag);
|
||||
node.tag = parenthesizerRules().parenthesizeLeftSideOfAccess(tag, /*optionalChain*/ false);
|
||||
node.typeArguments = asNodeArray(typeArguments);
|
||||
node.template = template;
|
||||
node.transformFlags |=
|
||||
@@ -3085,7 +3085,7 @@ namespace ts {
|
||||
// @api
|
||||
function createExpressionWithTypeArguments(expression: Expression, typeArguments: readonly TypeNode[] | undefined) {
|
||||
const node = createBaseNode<ExpressionWithTypeArguments>(SyntaxKind.ExpressionWithTypeArguments);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false);
|
||||
node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(typeArguments);
|
||||
node.transformFlags |=
|
||||
propagateChildFlags(node.expression) |
|
||||
@@ -3125,7 +3125,7 @@ namespace ts {
|
||||
// @api
|
||||
function createNonNullExpression(expression: Expression) {
|
||||
const node = createBaseExpression<NonNullExpression>(SyntaxKind.NonNullExpression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false);
|
||||
node.transformFlags |=
|
||||
propagateChildFlags(node.expression) |
|
||||
TransformFlags.ContainsTypeScript;
|
||||
@@ -3146,7 +3146,7 @@ namespace ts {
|
||||
function createNonNullChain(expression: Expression) {
|
||||
const node = createBaseExpression<NonNullChain>(SyntaxKind.NonNullExpression);
|
||||
node.flags |= NodeFlags.OptionalChain;
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
|
||||
node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ true);
|
||||
node.transformFlags |=
|
||||
propagateChildFlags(node.expression) |
|
||||
TransformFlags.ContainsTypeScript;
|
||||
@@ -5824,7 +5824,7 @@ namespace ts {
|
||||
}
|
||||
else if (getEmitFlags(callee) & EmitFlags.HelperName) {
|
||||
thisArg = createVoidZero();
|
||||
target = parenthesizerRules().parenthesizeLeftSideOfAccess(callee);
|
||||
target = parenthesizerRules().parenthesizeLeftSideOfAccess(callee, /*optionalChain*/ false);
|
||||
}
|
||||
else if (isPropertyAccessExpression(callee)) {
|
||||
if (shouldBeCapturedInTempVariable(callee.expression, cacheIdentifiers)) {
|
||||
@@ -5871,7 +5871,7 @@ namespace ts {
|
||||
else {
|
||||
// for `a()` target is `a` and thisArg is `void 0`
|
||||
thisArg = createVoidZero();
|
||||
target = parenthesizerRules().parenthesizeLeftSideOfAccess(expression);
|
||||
target = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false);
|
||||
}
|
||||
|
||||
return { target, thisArg };
|
||||
|
||||
@@ -319,7 +319,7 @@ namespace ts {
|
||||
* Wraps an expression in parentheses if it is needed in order to use the expression for
|
||||
* property or element access.
|
||||
*/
|
||||
function parenthesizeLeftSideOfAccess(expression: Expression): LeftHandSideExpression {
|
||||
function parenthesizeLeftSideOfAccess(expression: Expression, optionalChain?: boolean): LeftHandSideExpression {
|
||||
// isLeftHandSideExpression is almost the correct criterion for when it is not necessary
|
||||
// to parenthesize the expression before a dot. The known exception is:
|
||||
//
|
||||
@@ -328,7 +328,8 @@ namespace ts {
|
||||
//
|
||||
const emittedExpression = skipPartiallyEmittedExpressions(expression);
|
||||
if (isLeftHandSideExpression(emittedExpression)
|
||||
&& (emittedExpression.kind !== SyntaxKind.NewExpression || (emittedExpression as NewExpression).arguments)) {
|
||||
&& (emittedExpression.kind !== SyntaxKind.NewExpression || (emittedExpression as NewExpression).arguments)
|
||||
&& (optionalChain || !isOptionalChain(emittedExpression))) {
|
||||
// TODO(rbuckton): Verify whether this assertion holds.
|
||||
return expression as LeftHandSideExpression;
|
||||
}
|
||||
|
||||
@@ -7347,7 +7347,7 @@ namespace ts {
|
||||
parenthesizeBranchOfConditionalExpression(branch: Expression): Expression;
|
||||
parenthesizeExpressionOfExportDefault(expression: Expression): Expression;
|
||||
parenthesizeExpressionOfNew(expression: Expression): LeftHandSideExpression;
|
||||
parenthesizeLeftSideOfAccess(expression: Expression): LeftHandSideExpression;
|
||||
parenthesizeLeftSideOfAccess(expression: Expression, optionalChain?: boolean): LeftHandSideExpression;
|
||||
parenthesizeOperandOfPostfixUnary(operand: Expression): LeftHandSideExpression;
|
||||
parenthesizeOperandOfPrefixUnary(operand: Expression): UnaryExpression;
|
||||
parenthesizeExpressionsOfCommaDelimitedList(elements: readonly Expression[]): NodeArray<Expression>;
|
||||
|
||||
+1
-1
@@ -16,5 +16,5 @@ a?.b.d
|
||||
|
||||
|
||||
//// [optionalChainWithInstantiationExpression1.js]
|
||||
a?.b.d;
|
||||
(a?.b).d;
|
||||
a?.b.d;
|
||||
|
||||
@@ -10,7 +10,12 @@ const foo = new Foo();
|
||||
|
||||
/*a1*/(/*a2*/foo.m as any/*a3*/)/*a4*/?.();
|
||||
/*b1*/(/*b2*/<any>foo.m/*b3*/)/*b4*/?.();
|
||||
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/50148
|
||||
(foo?.m as any).length;
|
||||
(<any>foo?.m).length;
|
||||
(foo?.["m"] as any).length;
|
||||
(<any>foo?.["m"]).length;
|
||||
|
||||
//// [optionalChainingInTypeAssertions.js]
|
||||
var _a, _b, _c, _d;
|
||||
@@ -22,3 +27,8 @@ const foo = new Foo();
|
||||
(_b = foo.m) === null || _b === void 0 ? void 0 : _b.call(foo);
|
||||
/*a1*/ (_c = /*a2*/ foo.m /*a3*/ /*a4*/) === null || _c === void 0 ? void 0 : _c.call(foo);
|
||||
/*b1*/ (_d = /*b2*/ foo.m /*b3*/ /*b4*/) === null || _d === void 0 ? void 0 : _d.call(foo);
|
||||
// https://github.com/microsoft/TypeScript/issues/50148
|
||||
(foo === null || foo === void 0 ? void 0 : foo.m).length;
|
||||
(foo === null || foo === void 0 ? void 0 : foo.m).length;
|
||||
(foo === null || foo === void 0 ? void 0 : foo["m"]).length;
|
||||
(foo === null || foo === void 0 ? void 0 : foo["m"]).length;
|
||||
|
||||
@@ -30,3 +30,22 @@ const foo = new Foo();
|
||||
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
|
||||
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/50148
|
||||
(foo?.m as any).length;
|
||||
>foo?.m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
|
||||
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
|
||||
(<any>foo?.m).length;
|
||||
>foo?.m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
|
||||
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
|
||||
(foo?.["m"] as any).length;
|
||||
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
|
||||
>"m" : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
|
||||
(<any>foo?.["m"]).length;
|
||||
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
|
||||
>"m" : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
|
||||
|
||||
@@ -43,3 +43,40 @@ const foo = new Foo();
|
||||
>foo : Foo
|
||||
>m : () => void
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/50148
|
||||
(foo?.m as any).length;
|
||||
>(foo?.m as any).length : any
|
||||
>(foo?.m as any) : any
|
||||
>foo?.m as any : any
|
||||
>foo?.m : () => void
|
||||
>foo : Foo
|
||||
>m : () => void
|
||||
>length : any
|
||||
|
||||
(<any>foo?.m).length;
|
||||
>(<any>foo?.m).length : any
|
||||
>(<any>foo?.m) : any
|
||||
><any>foo?.m : any
|
||||
>foo?.m : () => void
|
||||
>foo : Foo
|
||||
>m : () => void
|
||||
>length : any
|
||||
|
||||
(foo?.["m"] as any).length;
|
||||
>(foo?.["m"] as any).length : any
|
||||
>(foo?.["m"] as any) : any
|
||||
>foo?.["m"] as any : any
|
||||
>foo?.["m"] : () => void
|
||||
>foo : Foo
|
||||
>"m" : "m"
|
||||
>length : any
|
||||
|
||||
(<any>foo?.["m"]).length;
|
||||
>(<any>foo?.["m"]).length : any
|
||||
>(<any>foo?.["m"]) : any
|
||||
><any>foo?.["m"] : any
|
||||
>foo?.["m"] : () => void
|
||||
>foo : Foo
|
||||
>"m" : "m"
|
||||
>length : any
|
||||
|
||||
|
||||
@@ -10,7 +10,12 @@ const foo = new Foo();
|
||||
|
||||
/*a1*/(/*a2*/foo.m as any/*a3*/)/*a4*/?.();
|
||||
/*b1*/(/*b2*/<any>foo.m/*b3*/)/*b4*/?.();
|
||||
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/50148
|
||||
(foo?.m as any).length;
|
||||
(<any>foo?.m).length;
|
||||
(foo?.["m"] as any).length;
|
||||
(<any>foo?.["m"]).length;
|
||||
|
||||
//// [optionalChainingInTypeAssertions.js]
|
||||
class Foo {
|
||||
@@ -21,3 +26,8 @@ foo.m?.();
|
||||
foo.m?.();
|
||||
/*a1*/ /*a2*/ foo.m /*a3*/ /*a4*/?.();
|
||||
/*b1*/ /*b2*/ foo.m /*b3*/ /*b4*/?.();
|
||||
// https://github.com/microsoft/TypeScript/issues/50148
|
||||
(foo?.m).length;
|
||||
(foo?.m).length;
|
||||
(foo?.["m"]).length;
|
||||
(foo?.["m"]).length;
|
||||
|
||||
@@ -30,3 +30,22 @@ const foo = new Foo();
|
||||
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
|
||||
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/50148
|
||||
(foo?.m as any).length;
|
||||
>foo?.m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
|
||||
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
|
||||
(<any>foo?.m).length;
|
||||
>foo?.m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
|
||||
>m : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
|
||||
(foo?.["m"] as any).length;
|
||||
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
|
||||
>"m" : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
|
||||
(<any>foo?.["m"]).length;
|
||||
>foo : Symbol(foo, Decl(optionalChainingInTypeAssertions.ts, 4, 5))
|
||||
>"m" : Symbol(Foo.m, Decl(optionalChainingInTypeAssertions.ts, 0, 11))
|
||||
|
||||
|
||||
@@ -43,3 +43,40 @@ const foo = new Foo();
|
||||
>foo : Foo
|
||||
>m : () => void
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/50148
|
||||
(foo?.m as any).length;
|
||||
>(foo?.m as any).length : any
|
||||
>(foo?.m as any) : any
|
||||
>foo?.m as any : any
|
||||
>foo?.m : () => void
|
||||
>foo : Foo
|
||||
>m : () => void
|
||||
>length : any
|
||||
|
||||
(<any>foo?.m).length;
|
||||
>(<any>foo?.m).length : any
|
||||
>(<any>foo?.m) : any
|
||||
><any>foo?.m : any
|
||||
>foo?.m : () => void
|
||||
>foo : Foo
|
||||
>m : () => void
|
||||
>length : any
|
||||
|
||||
(foo?.["m"] as any).length;
|
||||
>(foo?.["m"] as any).length : any
|
||||
>(foo?.["m"] as any) : any
|
||||
>foo?.["m"] as any : any
|
||||
>foo?.["m"] : () => void
|
||||
>foo : Foo
|
||||
>"m" : "m"
|
||||
>length : any
|
||||
|
||||
(<any>foo?.["m"]).length;
|
||||
>(<any>foo?.["m"]).length : any
|
||||
>(<any>foo?.["m"]) : any
|
||||
><any>foo?.["m"] : any
|
||||
>foo?.["m"] : () => void
|
||||
>foo : Foo
|
||||
>"m" : "m"
|
||||
>length : any
|
||||
|
||||
|
||||
+6
@@ -11,3 +11,9 @@ const foo = new Foo();
|
||||
|
||||
/*a1*/(/*a2*/foo.m as any/*a3*/)/*a4*/?.();
|
||||
/*b1*/(/*b2*/<any>foo.m/*b3*/)/*b4*/?.();
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/50148
|
||||
(foo?.m as any).length;
|
||||
(<any>foo?.m).length;
|
||||
(foo?.["m"] as any).length;
|
||||
(<any>foo?.["m"]).length;
|
||||
Reference in New Issue
Block a user