Skip to content
This repository was archived by the owner on Mar 25, 2021. It is now read-only.

Commit 44947c5

Browse files
guidsdoJosh Goldberg
authored and
Josh Goldberg
committed
Fix bug where the strict ts flag wasn't recognised correctly by no-unnecessary-type-assertion (#4841)
* Fix bug where the strict ts flag wasn't recognised correctly This commit fixes #4840 * Make sure to only test 'strict' flag option for tsc 2.4+ * Review: put getCompilerOptions into var
1 parent 89d731f commit 44947c5

File tree

5 files changed

+246
-1
lines changed

5 files changed

+246
-1
lines changed

src/rules/noUnnecessaryTypeAssertionRule.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,18 @@ export class Rule extends Lint.Rules.TypedRule {
4444
"This assertion is unnecessary since it does not change the type of the expression.";
4545

4646
public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
47+
const compilerOptions = program.getCompilerOptions();
48+
const strictChecksEnabled = !!compilerOptions.strict;
49+
const strictNullChecksEnabled = compilerOptions.strictNullChecks === true;
50+
const strictNullChecksNotDisabled = compilerOptions.strictNullChecks !== false;
51+
4752
return this.applyWithWalker(
4853
new Walker(
4954
sourceFile,
5055
this.ruleName,
5156
this.ruleArguments,
5257
program.getTypeChecker(),
53-
!!program.getCompilerOptions().strictNullChecks,
58+
strictNullChecksEnabled || (strictChecksEnabled && strictNullChecksNotDisabled),
5459
),
5560
);
5661
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
const nonNullStringLiteral: 'test';
2+
const nonNullString: string;
3+
const nullableString: string|undefined;
4+
let anyType: any;
5+
type AnyDuringMigration = any;
6+
let tuple: [number, number] = [1, 2];
7+
8+
// non-null
9+
let a = nonNullStringLiteral;
10+
let b = nonNullString;
11+
let c = nullableString!;
12+
tuple;
13+
14+
// as
15+
let d = nonNullStringLiteral as string;
16+
let e = nonNullString;
17+
let f = nullableString as string;
18+
19+
// type assertion
20+
let g = <string>nonNullStringLiteral;
21+
let h = nonNullString;
22+
let i = <string>nullableString;
23+
24+
// complex inner expression
25+
let j = (nonNullString + nonNullStringLiteral);
26+
let k = (nonNullString + nonNullStringLiteral);
27+
let l = (nonNullString + nonNullStringLiteral);
28+
let m = nonNullString.trim();
29+
let n = nonNullString.trim();
30+
let o = nonNullString.trim();
31+
let p = nonNullString.trim();
32+
33+
// custom types
34+
interface Iface1 {
35+
prop: string;
36+
}
37+
interface Iface2 {
38+
prop: string;
39+
}
40+
41+
const value1: Iface1 = {prop: 'test'};
42+
const value2: Iface2 = {prop: 'test'};
43+
44+
let q = value1;
45+
let r = <Iface2>value1;
46+
let s = value2;
47+
let t = value2 as Iface1;
48+
let aa = anyType as AnyDuringMigration;
49+
50+
interface TypeA {
51+
kind: 'a';
52+
}
53+
interface TypeB {
54+
kind: 'b';
55+
}
56+
57+
function isB(x: TypeA|TypeB): x is TypeB {
58+
return true;
59+
}
60+
61+
function func(aOrB: TypeA|TypeB) {
62+
let u = aOrB as TypeA;
63+
let v = <TypeB>aOrB;
64+
65+
if (aOrB.kind === 'a') {
66+
let w = aOrB;
67+
} else {
68+
let x = aOrB;
69+
}
70+
71+
if (isB(aOrB)) {
72+
let y = aOrB;
73+
} else {
74+
let z = aOrB;
75+
}
76+
}
77+
78+
// Expecting no warning for these assertions as they are not unnecessary.
79+
80+
type Bar = 'bar';
81+
const data = {
82+
x: 'foo' as 'foo',
83+
y: 'bar' as Bar,
84+
}
85+
86+
[1, 2, 3, 4, 5].map(x => [x, 'A' + x] as [number, string]);
87+
let x: Array<[number, string]> = [1, 2, 3, 4, 5].map(x => [x, 'A' + x] as [number, string]);
88+
89+
interface NotATuple {
90+
0: number,
91+
0.5: number,
92+
2: number,
93+
}
94+
95+
declare const notATuple: NotATuple;
96+
notATuple;
97+
98+
function foo() {
99+
let xx: 1 | 2 = 1;
100+
const f = () => xx = 2;
101+
f();
102+
xx as 1 | 2 === 2; // xx is inferred as 1, assertion is necessary to avoid compile error
103+
}
104+
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
[typescript]: >= 2.4.0
2+
const nonNullStringLiteral: 'test';
3+
const nonNullString: string;
4+
const nullableString: string|undefined;
5+
let anyType: any;
6+
type AnyDuringMigration = any;
7+
let tuple: [number, number] = [1, 2];
8+
9+
// non-null
10+
let a = nonNullStringLiteral!;
11+
~~~~~~~~~~~~~~~~~~~~~ [0]
12+
let b = nonNullString!;
13+
~~~~~~~~~~~~~~ [0]
14+
let c = nullableString!;
15+
tuple!;
16+
~~~~~~ [0]
17+
18+
// as
19+
let d = nonNullStringLiteral as string;
20+
let e = nonNullString as string;
21+
~~~~~~~~~~~~~~~~~~~~~~~ [0]
22+
let f = nullableString as string;
23+
24+
// type assertion
25+
let g = <string>nonNullStringLiteral;
26+
let h = <string>nonNullString;
27+
~~~~~~~~~~~~~~~~~~~~~ [0]
28+
let i = <string>nullableString;
29+
30+
// complex inner expression
31+
let j = (nonNullString + nonNullStringLiteral)!;
32+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
33+
let k = (nonNullString + nonNullStringLiteral) as string;
34+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
35+
let l = <string>(nonNullString + nonNullStringLiteral);
36+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
37+
let m = nonNullString.trim()!;
38+
~~~~~~~~~~~~~~~~~~~~~ [0]
39+
let n = nonNullString.trim() as string;
40+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
41+
let o = <string>nonNullString.trim();
42+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
43+
let p = nonNullString!.trim();
44+
~~~~~~~~~~~~~~ [0]
45+
46+
// custom types
47+
interface Iface1 {
48+
prop: string;
49+
}
50+
interface Iface2 {
51+
prop: string;
52+
}
53+
54+
const value1: Iface1 = {prop: 'test'};
55+
const value2: Iface2 = {prop: 'test'};
56+
57+
let q = <Iface1>value1;
58+
~~~~~~~~~~~~~~ [0]
59+
let r = <Iface2>value1;
60+
let s = value2 as Iface2;
61+
~~~~~~~~~~~~~~~~ [0]
62+
let t = value2 as Iface1;
63+
let aa = anyType as AnyDuringMigration;
64+
65+
interface TypeA {
66+
kind: 'a';
67+
}
68+
interface TypeB {
69+
kind: 'b';
70+
}
71+
72+
function isB(x: TypeA|TypeB): x is TypeB {
73+
return true;
74+
}
75+
76+
function func(aOrB: TypeA|TypeB) {
77+
let u = aOrB as TypeA;
78+
let v = <TypeB>aOrB;
79+
80+
if (aOrB.kind === 'a') {
81+
let w = aOrB as TypeA;
82+
~~~~~~~~~~~~~ [0]
83+
} else {
84+
let x = <TypeB>aOrB;
85+
~~~~~~~~~~~ [0]
86+
}
87+
88+
if (isB(aOrB)) {
89+
let y = aOrB as TypeB;
90+
~~~~~~~~~~~~~ [0]
91+
} else {
92+
let z = <TypeA>aOrB;
93+
~~~~~~~~~~~ [0]
94+
}
95+
}
96+
97+
// Expecting no warning for these assertions as they are not unnecessary.
98+
99+
type Bar = 'bar';
100+
const data = {
101+
x: 'foo' as 'foo',
102+
y: 'bar' as Bar,
103+
}
104+
105+
[1, 2, 3, 4, 5].map(x => [x, 'A' + x] as [number, string]);
106+
let x: Array<[number, string]> = [1, 2, 3, 4, 5].map(x => [x, 'A' + x] as [number, string]);
107+
108+
interface NotATuple {
109+
0: number,
110+
0.5: number,
111+
2: number,
112+
}
113+
114+
declare const notATuple: NotATuple;
115+
<NotATuple>notATuple;
116+
~~~~~~~~~~~~~~~~~~~~ [0]
117+
118+
function foo() {
119+
let xx: 1 | 2 = 1;
120+
const f = () => xx = 2;
121+
f();
122+
xx as 1 | 2 === 2; // xx is inferred as 1, assertion is necessary to avoid compile error
123+
}
124+
125+
[0]: This assertion is unnecessary since it does not change the type of the expression.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2015",
4+
"strict": true
5+
}
6+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"rules": {
3+
"no-unnecessary-type-assertion": [true, "AnyDuringMigration"]
4+
}
5+
}

0 commit comments

Comments
 (0)