β¬ οΈ Back to Table of Contents
π no-meaningless-void-operator¶
π Analysis Summary¶
| Metric | Count |
|---|---|
| π§ Functions | 3 |
| π¦ Imports | 6 |
| π Type Aliases | 1 |
π Table of Contents¶
π οΈ File Location:¶
π packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts
π€ Default Export¶
export default createRule<Options, 'meaninglessVoidOnNonCall' | 'meaninglessVoidOperator' | 'removeVoid'>({ ... })
| Property | Value |
|---|---|
name |
'no-meaningless-void-operator' |
meta.type |
'suggestion' |
meta.docs.description |
'Disallow the void operator except when used to discard a value' |
meta.docs.recommended |
'strict' |
meta.docs.requiresTypeChecking |
true |
meta.fixable |
'code' |
meta.hasSuggestions |
true |
meta.messages.meaninglessVoidOnNonCall |
"void operator is useless here; it should only discard a call's return value" |
meta.messages.meaninglessVoidOperator |
"void operator shouldn't be used on {{type}}; it should convey that a return value is being ignored" |
meta.messages.removeVoid |
"Remove 'void'" |
meta.schema |
[ { type: 'object', additionalProperties: false, properties: { checkNever: { type: 'boolean', description: "Whether t... |
defaultOptions |
[{ checkNever: false }] |
Entry point: create β documented under Functions.
π¦ Imports¶
| Name | Source |
|---|---|
TSESLint |
@typescript-eslint/utils |
TSESTree |
@typescript-eslint/utils |
AST_NODE_TYPES |
@typescript-eslint/utils |
ESLintUtils |
@typescript-eslint/utils |
createRule |
../util |
nullThrows |
../util |
Functions¶
create(context: any, [{ checkNever }]: any): { 'UnaryExpression[operator="void"]'(node: TSESTree.UnaryEx⦶
Parameters:
contextany[{ checkNever }]any
Returns: { 'UnaryExpression[operator="void"]'(node: TSESTree.UnaryExpression): void; }
Calls:
ESLintUtils.getParserServicesservices.program.getTypeCheckerfixer.removeRangecontext.sourceCode.getTokensunwrapVoidArgumentservices.esTreeNodeToTSNodeMap.getservices.getTypeAtLocationtsutils.isThenableTypecontext.reporttsutils.unionConstituentsunionParts.everytsutils.isTypeFlagSetchecker.typeToString
Internal Comments:
// `void 0` is a common undefined idiom, not a discarded call.
// Allow `void promiseValue` so this rule does not fight no-floating-promises.
Code
create(context, [{ checkNever }]) {
const services = ESLintUtils.getParserServices(context);
const checker = services.program.getTypeChecker();
return {
'UnaryExpression[operator="void"]'(node: TSESTree.UnaryExpression): void {
const fix = (fixer: TSESLint.RuleFixer): TSESLint.RuleFix => {
return fixer.removeRange([
context.sourceCode.getTokens(node)[0].range[0],
context.sourceCode.getTokens(node)[1].range[0],
]);
};
const inner = unwrapVoidArgument(node.argument);
if (inner.type !== AST_NODE_TYPES.CallExpression) {
// `void 0` is a common undefined idiom, not a discarded call.
if (inner.type === AST_NODE_TYPES.Literal && inner.value === 0) {
return;
}
const tsArgument = services.esTreeNodeToTSNodeMap.get(node.argument);
const argType = services.getTypeAtLocation(node.argument);
// Allow `void promiseValue` so this rule does not fight no-floating-promises.
if (tsutils.isThenableType(checker, tsArgument, argType)) {
return;
}
context.report({
node,
messageId: 'meaninglessVoidOnNonCall',
fix:
node.parent.type === AST_NODE_TYPES.ExpressionStatement
? fix
: undefined,
});
return;
}
const argType = services.getTypeAtLocation(node.argument);
const unionParts = tsutils.unionConstituents(argType);
if (
unionParts.every(part =>
tsutils.isTypeFlagSet(
part,
ts.TypeFlags.Void | ts.TypeFlags.Undefined,
),
)
) {
context.report({
node,
messageId: 'meaninglessVoidOperator',
data: { type: checker.typeToString(argType) },
fix,
});
} else if (
checkNever &&
unionParts.every(part =>
tsutils.isTypeFlagSet(
part,
ts.TypeFlags.Void | ts.TypeFlags.Undefined | ts.TypeFlags.Never,
),
)
) {
context.report({
node,
messageId: 'meaninglessVoidOperator',
data: { type: checker.typeToString(argType) },
suggest: [{ messageId: 'removeVoid', fix }],
});
}
},
};
}
unwrapVoidArgument(node: TSESTree.Expression): TSESTree.Expression¶
Parameters:
nodeTSESTree.Expression
Returns: TSESTree.Expression
Calls:
nullThrows (from ../util)current.expressions.at
Code
function unwrapVoidArgument(node: TSESTree.Expression): TSESTree.Expression {
let current = node;
while (true) {
switch (current.type) {
case AST_NODE_TYPES.ChainExpression:
case AST_NODE_TYPES.TSAsExpression:
case AST_NODE_TYPES.TSNonNullExpression:
case AST_NODE_TYPES.TSSatisfiesExpression:
case AST_NODE_TYPES.TSTypeAssertion:
current = current.expression;
continue;
case AST_NODE_TYPES.SequenceExpression:
current = nullThrows(
current.expressions.at(-1),
'Expected SequenceExpression to have at least one expression',
);
continue;
default:
return current;
}
}
}
Internal helpers¶
Declared inside another function in this file.
fix(fixer: TSESLint.RuleFixer): TSESLint.RuleFix¶
Parameters:
fixerTSESLint.RuleFixer
Returns: TSESLint.RuleFix
Calls:
fixer.removeRangecontext.sourceCode.getTokens
Code
Type Aliases¶
Options¶
Generated by Syntax Scribe