Skip to content

Commit 76b14a4

Browse files
nrathiadidahiya
authored andcommitted
Relax "no-null-undefined-union" rule. (palantir#4625)
1 parent 5432570 commit 76b14a4

File tree

3 files changed

+60
-45
lines changed

3 files changed

+60
-45
lines changed

src/configuration.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,6 @@ export function getRulesDirectories(
429429
* @param ruleConfigValue The raw option setting of a rule
430430
*/
431431
function parseRuleOptions(
432-
// tslint:disable-next-line no-null-undefined-union
433432
ruleConfigValue: RawRuleConfig,
434433
rawDefaultRuleSeverity: string | undefined,
435434
): Partial<IOptions> {
@@ -508,12 +507,11 @@ export interface RawConfigFile {
508507
jsRules?: RawRulesConfig | boolean;
509508
}
510509
export interface RawRulesConfig {
511-
// tslint:disable-next-line no-null-undefined-union
512510
[key: string]: RawRuleConfig;
513511
}
514512

515-
// tslint:disable-next-line no-null-undefined-union
516513
export type RawRuleConfig =
514+
// tslint:disable-next-line no-null-undefined-union
517515
| null
518516
| undefined
519517
| boolean

src/rules/noNullUndefinedUnionRule.ts

+9-22
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
import {
19-
isParameterDeclaration,
20-
isPropertyDeclaration,
21-
isPropertySignature,
22-
isSignatureDeclaration,
23-
isTypeAliasDeclaration,
24-
isTypeReference,
25-
isUnionType,
26-
isVariableDeclaration,
27-
} from "tsutils";
18+
import { isSignatureDeclaration, isTypeReference, isUnionType, isUnionTypeNode } from "tsutils";
2819
import * as ts from "typescript";
2920

3021
import * as Lint from "../index";
@@ -33,11 +24,15 @@ export class Rule extends Lint.Rules.TypedRule {
3324
/* tslint:disable:object-literal-sort-keys */
3425
public static metadata: Lint.IRuleMetadata = {
3526
ruleName: "no-null-undefined-union",
36-
description: "Disallows union types with both `null` and `undefined` as members.",
27+
description: Lint.Utils.dedent`
28+
Disallows explicitly declared or implicitly returned union types with both \`null\` and
29+
\`undefined\` as members.
30+
`,
3731
rationale: Lint.Utils.dedent`
3832
A union type that includes both \`null\` and \`undefined\` is either redundant or fragile.
3933
Enforcing the choice between the two allows the \`triple-equals\` rule to exist without
4034
exceptions, and is essentially a more flexible version of the \`no-null-keyword\` rule.
35+
Optional parameters are not considered to have the type \`undefined\`.
4136
`,
4237
optionsDescription: "Not configurable.",
4338
options: null,
@@ -66,18 +61,10 @@ function walk(ctx: Lint.WalkContext, tc: ts.TypeChecker): void {
6661
}
6762

6863
function getType(node: ts.Node, tc: ts.TypeChecker): ts.Type | undefined {
69-
// This is a comprehensive intersection between `HasType` and has property `name`.
70-
// The node name kind must be identifier, or else this rule will throw errors while descending.
71-
if (
72-
(isVariableDeclaration(node) ||
73-
isParameterDeclaration(node) ||
74-
isPropertySignature(node) ||
75-
isPropertyDeclaration(node) ||
76-
isTypeAliasDeclaration(node)) &&
77-
node.name.kind === ts.SyntaxKind.Identifier
78-
) {
64+
if (isUnionTypeNode(node)) {
7965
return tc.getTypeAtLocation(node);
80-
} else if (isSignatureDeclaration(node)) {
66+
} else if (isSignatureDeclaration(node) && node.type === undefined) {
67+
// Explicit types should be handled by the first case.
8168
const signature = tc.getSignatureFromDeclaration(node);
8269
return signature === undefined ? undefined : signature.getReturnType();
8370
} else {
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,40 @@
11
[typescript]: >= 2.4.0
22

3-
interface someInterface {
4-
a: number | undefined | null;
5-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
6-
b: boolean;
7-
}
3+
// Catches explicit union types.
84

9-
const c: string | null | undefined;
10-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
5+
type SomeType =
116

12-
export type SomeType =
13-
~~~~~~~~~~~~~~~~~~~~~~
147
| null
15-
~~~~~~~~~~
8+
~~~~
169
| undefined
1710
~~~~~~~~~~~~~~~
1811
| boolean;
19-
~~~~~~~~~~~~~~ [0]
12+
~~~~~~~~~~~~~ [0]
13+
14+
const c: string | null | undefined;
15+
~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
2016

2117
const someFunc = (): string | undefined | null => {}
22-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
18+
~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
2319

2420
const someFunc = (foo: null | string | undefined, bar: boolean) => {}
25-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
21+
~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
22+
23+
interface SomeInterface {
24+
foo: number | null | undefined;
25+
~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
26+
bar: boolean;
27+
}
2628

27-
function someFunc(): number | undefined | null {}
28-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
29+
function someFunc(): Promise<number | undefined | null> {} // error
30+
~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
2931

30-
function someFunc(): Promise<number | null | undefined> {} // error
31-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
32+
function someFunc(bar: boolean, foo: undefined | number | null) {}
33+
~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
3234

33-
function someFunc(bar: boolean, foo: null | number | undefined) {}
34-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
35+
// Catches implicit return types.
3536

36-
function someFunc() {
37+
function testFunc() {
3738
~~~~~~~~~~~~~~~~~~~~~
3839
const somePredicate = (): boolean => true;
3940
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -52,4 +53,33 @@ function someFunc() {
5253
}
5354
~ [0]
5455

56+
// Does not consider ? as shorthand for undefined.
57+
58+
type Text = string | null
59+
60+
interface TextInterface {
61+
foo?: Text
62+
}
63+
64+
interface SuperTextInterface {
65+
bar?: Text | number
66+
}
67+
68+
function someFunc(foo?: Text, bar?: Text | number) {}
69+
70+
// Ignores implicit union types.
71+
72+
const x: SomeType;
73+
74+
const someFunc = (): SomeType => {}
75+
76+
function(foo: SomeInterface) {}
77+
78+
const y = testFunc();
79+
80+
// Unless they are explicitly unioned.
81+
82+
const z: Text | undefined;
83+
~~~~~~~~~~~~~~~~ [0]
84+
5585
[0]: Union type cannot include both 'null' and 'undefined'.

0 commit comments

Comments
 (0)