From b1d9034b384b2e64aea7ab4133acef0fd092104b Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Fri, 21 Aug 2020 18:57:21 -0700 Subject: [PATCH] Use 'void' for the contextual type of an unused expression --- src/compiler/checker.ts | 25 ++++++++++++++++++++++--- src/compiler/types.ts | 2 +- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a85281375e6..819cd98f6fd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23042,7 +23042,7 @@ namespace ts { if (result) { return result; } - if (!(contextFlags! & ContextFlags.SkipBindingPatterns) && isBindingPattern(declaration.name)) { // This is less a contextual type and more an implied shape - in some cases, this may be undesirable + if (!(contextFlags! & ContextFlags.SkipBindingPatternsAndUnusedExpressions) && isBindingPattern(declaration.name)) { // This is less a contextual type and more an implied shape - in some cases, this may be undesirable return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ true, /*reportErrors*/ false); } } @@ -23190,7 +23190,13 @@ namespace ts { getTypeOfExpression(left) : type; case SyntaxKind.AmpersandAmpersandToken: case SyntaxKind.CommaToken: - return node === right ? getContextualType(binaryExpression, contextFlags) : undefined; + if (node === right) { + return getContextualType(binaryExpression, contextFlags); + } + else if (!(contextFlags! & ContextFlags.SkipBindingPatternsAndUnusedExpressions)) { + return voidType; + } + return undefined; default: return undefined; } @@ -23602,6 +23608,19 @@ namespace ts { case SyntaxKind.JsxOpeningElement: case SyntaxKind.JsxSelfClosingElement: return getContextualJsxElementAttributesType(parent, contextFlags); + case SyntaxKind.ExpressionStatement: + case SyntaxKind.VoidExpression: + if (!(contextFlags! & ContextFlags.SkipBindingPatternsAndUnusedExpressions)) { + return voidType; + } + break; + case SyntaxKind.ForStatement: { + const forStatement = parent as ForStatement; + if (!(contextFlags! & ContextFlags.SkipBindingPatternsAndUnusedExpressions) && (node === forStatement.initializer || node === forStatement.incrementor)) { + return voidType; + } + break; + } } return undefined; @@ -25919,7 +25938,7 @@ namespace ts { // 'let f: (x: string) => number = wrap(s => s.length)', we infer from the declared type of 'f' to the // return type of 'wrap'. if (node.kind !== SyntaxKind.Decorator) { - const contextualType = getContextualType(node, every(signature.typeParameters, p => !!getDefaultFromTypeParameter(p)) ? ContextFlags.SkipBindingPatterns : ContextFlags.None); + const contextualType = getContextualType(node, every(signature.typeParameters, p => !!getDefaultFromTypeParameter(p)) ? ContextFlags.SkipBindingPatternsAndUnusedExpressions : ContextFlags.None); if (contextualType) { // We clone the inference context to avoid disturbing a resolution in progress for an // outer call expression. Effectively we just want a snapshot of whatever has been diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 40f43b3ad6b..0fd0345c9c7 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4139,7 +4139,7 @@ namespace ts { Signature = 1 << 0, // Obtaining contextual signature NoConstraints = 1 << 1, // Don't obtain type variable constraints Completions = 1 << 2, // Ignore inference to current node and parent nodes out to the containing call for completions - SkipBindingPatterns = 1 << 3, // Ignore contextual types applied by binding patterns + SkipBindingPatternsAndUnusedExpressions = 1 << 3, // Ignore contextual types applied by binding patterns and do not use `void` as the contextual type for unused expressions } // NOTE: If modifying this enum, must modify `TypeFormatFlags` too!