Skip to content

Commit

Permalink
no-useless-assertion: forbid non-null assertion on type parameter
Browse files Browse the repository at this point in the history
This doesn't work until subtraction types are implemented.
Ref: microsoft/TypeScript#20974
  • Loading branch information
ajafff committed Jan 2, 2018
1 parent 9b21cc9 commit f8d880f
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 9 deletions.
8 changes: 5 additions & 3 deletions src/rules/no-useless-assertion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,16 @@ export class Rule extends TypedRule {
private checkNonNullAssertion(node: ts.NonNullExpression) {
let message = FAIL_MESSAGE;
if (this.strictNullChecks) {
const flags = getNullableFlags(this.checker.getApparentType(this.checker.getTypeAtLocation(node.expression)));
const originalType = this.checker.getTypeAtLocation(node.expression);
const flags = getNullableFlags(originalType);
if (flags !== 0) { // type is nullable
const contextualType = this.getSafeContextualType(node);
if (contextualType === undefined || (flags & ~getNullableFlags(contextualType, true)))
return;
message = `This assertion is unnecessary as the receiver accepts ${formatNullableFlags(flags)} values.`;
}
if (maybeUsedBeforeBeingAssigned(node.expression, this.checker)) {
} else if (originalType.flags & ts.TypeFlags.TypeParameter) {
message = "Non-null assertions don't work with type parameters.";
} else if (maybeUsedBeforeBeingAssigned(node.expression, this.checker)) {
log('Identifier %s could be used before being assigned', node.expression.text);
return;
}
Expand Down
10 changes: 10 additions & 0 deletions test/rules/no-useless-assertion/loose/non-null.ts.fix
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,13 @@ takeStringNumberUndefined(possiblyBoth);

declare let functionOrAny: (() => void) | undefined;
functionOrAny();

function fn<T extends string | undefined, U extends string, V>(one: T, two: U, three: V) {
one;
two;
fn(one, two);
foo(one);
fn(two, one);
foo(three);
takeUndefined(one);
}
19 changes: 19 additions & 0 deletions test/rules/no-useless-assertion/loose/non-null.ts.lint
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,22 @@ takeStringNumberUndefined(possiblyBoth!);
declare let functionOrAny: (() => void) | undefined;
functionOrAny!();
~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]

function fn<T extends string | undefined, U extends string, V>(one: T, two: U, three: V) {
one!;
~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
two!;
~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
fn(one!, two!);
~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
foo(one!);
~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
fn(two!, one!);
~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
foo(three!);
~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
takeUndefined(one!);
~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ function fn<T extends string | undefined>(param: T) {
param;
param;
param;
param;
b as T;
b = param;
param = b as T;
Expand Down
2 changes: 0 additions & 2 deletions test/rules/no-useless-assertion/loose/type-assertion.ts.lint
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ function fn<T extends string | undefined>(param: T) {
~~~~~~~~~~~~~~~~~~~~~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
param as typeof param;
~~~~~~~~~~~~~~~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
param!;
~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
b as T;
b = param;
param = b as T;
Expand Down
10 changes: 10 additions & 0 deletions test/rules/no-useless-assertion/non-null.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,13 @@ takeStringNumberUndefined(possiblyBoth!);

declare let functionOrAny: (() => void) | undefined;
functionOrAny!();

function fn<T extends string | undefined, U extends string, V>(one: T, two: U, three: V) {
one!;
two!;
fn(one!, two!);
foo(one!);
fn(two!, one!);
foo(three!);
takeUndefined(one!);
}
10 changes: 10 additions & 0 deletions test/rules/no-useless-assertion/strict/non-null.ts.fix
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,13 @@ takeStringNumberUndefined(possiblyBoth!);

declare let functionOrAny: (() => void) | undefined;
functionOrAny!();

function fn<T extends string | undefined, U extends string, V>(one: T, two: U, three: V) {
one;
two;
fn(one, two);
foo(one);
fn(two, one);
foo(three);
takeUndefined(one);
}
19 changes: 19 additions & 0 deletions test/rules/no-useless-assertion/strict/non-null.ts.lint
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,22 @@ takeStringNumberUndefined(possiblyBoth!);

declare let functionOrAny: (() => void) | undefined;
functionOrAny!();

function fn<T extends string | undefined, U extends string, V>(one: T, two: U, three: V) {
one!;
~ [error no-useless-assertion: Non-null assertions don't work with type parameters.]
two!;
~ [error no-useless-assertion: Non-null assertions don't work with type parameters.]
fn(one!, two!);
~ [error no-useless-assertion: Non-null assertions don't work with type parameters.]
~ [error no-useless-assertion: Non-null assertions don't work with type parameters.]
foo(one!);
~ [error no-useless-assertion: Non-null assertions don't work with type parameters.]
fn(two!, one!);
~ [error no-useless-assertion: Non-null assertions don't work with type parameters.]
~ [error no-useless-assertion: Non-null assertions don't work with type parameters.]
foo(three!);
~ [error no-useless-assertion: Non-null assertions don't work with type parameters.]
takeUndefined(one!);
~ [error no-useless-assertion: Non-null assertions don't work with type parameters.]
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ function fn<T extends string | undefined>(param: T) {
param as string;
param;
param;
param!;
b as T;
b = param;
param = b as T;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ function fn<T extends string | undefined>(param: T) {
~~~~~~~~~~~~~~~~~~~~~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
param as typeof param;
~~~~~~~~~~~~~~~ [error no-useless-assertion: This assertion is unnecesary as it doesn't change the type of the expression.]
param!;
b as T;
b = param;
param = b as T;
Expand Down
1 change: 0 additions & 1 deletion test/rules/no-useless-assertion/type-assertion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ function fn<T extends string | undefined>(param: T) {
param as string;
param as string | undefined;
param as typeof param;
param!;
b as T;
b = param;
param = b as T;
Expand Down

0 comments on commit f8d880f

Please sign in to comment.