diff --git a/src/rules/noNullKeywordRule.ts b/src/rules/noNullKeywordRule.ts index 1b3e6d5fd34..c963f11b75a 100644 --- a/src/rules/noNullKeywordRule.ts +++ b/src/rules/noNullKeywordRule.ts @@ -17,6 +17,7 @@ // with due reference to https://github.com/Microsoft/TypeScript/blob/7813121c4d77e50aad0eed3152ef1f1156c7b574/scripts/tslint/noNullRule.ts +import { isBinaryExpression, isTypeNodeKind } from "tsutils"; import * as ts from "typescript"; import * as Lint from "../index"; @@ -34,6 +35,7 @@ export class Rule extends Lint.Rules.AbstractRule { optionExamples: [true], type: "functionality", typescriptOnly: false, + hasFix: true, }; /* tslint:enable:object-literal-sort-keys */ @@ -47,12 +49,21 @@ export class Rule extends Lint.Rules.AbstractRule { function walk(ctx: Lint.WalkContext) { return ts.forEachChild(ctx.sourceFile, cb); function cb(node: ts.Node): void { - if (node.kind >= ts.SyntaxKind.FirstTypeNode && node.kind <= ts.SyntaxKind.LastTypeNode) { + if (isTypeNodeKind(node.kind)) { return; // skip type nodes } - if (node.kind === ts.SyntaxKind.NullKeyword) { - return ctx.addFailureAtNode(node, Rule.FAILURE_STRING); + if (node.kind !== ts.SyntaxKind.NullKeyword) { + return ts.forEachChild(node, cb); + } + const parent = node.parent!; + let eq: Lint.EqualsKind | undefined; + if (isBinaryExpression(parent)) { + eq = Lint.getEqualsKind(parent.operatorToken); + } + if (eq === undefined) { + ctx.addFailureAtNode(node, Rule.FAILURE_STRING); + } else if (!eq.isStrict) { + ctx.addFailureAtNode(node, Rule.FAILURE_STRING, Lint.Replacement.replaceNode(node, "undefined", ctx.sourceFile)); } - return ts.forEachChild(node, cb); } } diff --git a/test/rules/no-null-keyword/test.ts.fix b/test/rules/no-null-keyword/test.ts.fix new file mode 100644 index 00000000000..5a43ae107d8 --- /dev/null +++ b/test/rules/no-null-keyword/test.ts.fix @@ -0,0 +1,12 @@ +var x = null; // error +console.log(null, x); // error + +let match: string | null; +interface foo { + bar: [number, null, string]; +} + +if (document.querySelector('.foo') === null) {} +if (document.querySelector('.foo') == undefined) {} +if (null !== document.querySelector('.foo')) {} +if (undefined != document.querySelector('.foo')) {} diff --git a/test/rules/no-null-keyword/test.ts.lint b/test/rules/no-null-keyword/test.ts.lint index 5eb317ac348..92248e37a1f 100644 --- a/test/rules/no-null-keyword/test.ts.lint +++ b/test/rules/no-null-keyword/test.ts.lint @@ -1,9 +1,18 @@ var x = null; // error - ~~~~ [Use 'undefined' instead of 'null'] + ~~~~ [0] console.log(null, x); // error - ~~~~ [Use 'undefined' instead of 'null'] + ~~~~ [0] -let match(): string | null; +let match: string | null; interface foo { bar: [number, null, string]; } + +if (document.querySelector('.foo') === null) {} +if (document.querySelector('.foo') == null) {} + ~~~~ [0] +if (null !== document.querySelector('.foo')) {} +if (null != document.querySelector('.foo')) {} + ~~~~ [0] + +[0]: Use 'undefined' instead of 'null' \ No newline at end of file