Skip to content

Commit

Permalink
ffix(lint/noInferrableTypes): assume TypeScript unsafe null mode (#729)
Browse files Browse the repository at this point in the history
  • Loading branch information
Conaclos authored Nov 14, 2023
1 parent fc877aa commit 80a7987
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 225 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ Read our [guidelines for writing a good changelog entry](https://github.com/biom

- Fix [#455](https://github.com/biomejs/biome/issues/455). The CLI can now print complex emojis to the console correctly.

- Fix [#727](https://github.com/biomejs/biome/issues/727). [noInferrableTypes](https://biomejs.dev/linter/rules/no-inferrable-types) now correctly keeps type annotations when the initialization expression is `null`. Contributed by @Conaclos

### Parser

### VSCode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use biome_js_syntax::{
JsVariableDeclarator, JsVariableDeclaratorList, TsPropertyParameter, TsReadonlyModifier,
TsTypeAnnotation,
};
use biome_js_syntax::{AnyJsLiteralExpression, AnyTsType};
use biome_rowan::AstNode;
use biome_rowan::BatchMutationExt;

Expand Down Expand Up @@ -149,9 +150,24 @@ impl Rule for NoInferrableTypes {
// In const contexts, literal type annotations are rejected.
// e.g. `const x: 1 = <literal>`
//
// However, we ignore `null` and `undefined` literal types,
// because in unsafe null mode, TypeScript widen an unannotated variable to `any`.
//
// In non-const contexts, wide type annotation are rejected.
// e.g. `let x: number = <literal>`
if (is_const && ty.is_literal_type()) || (!is_const && ty.is_primitive_type()) {
//
// However, we ignore the case where <literal> is `null`,
// because in unsafe null mode, it is possible to assign `null` and `undefined` to any type.
if (is_const && is_non_null_literal_type(&ty))
|| (!is_const
&& ty.is_primitive_type()
&& !matches!(
init_expr,
AnyJsExpression::AnyJsLiteralExpression(
AnyJsLiteralExpression::JsNullLiteralExpression(_)
)
))
{
return Some(type_annotation);
}
}
Expand Down Expand Up @@ -206,3 +222,13 @@ fn has_trivially_inferrable_type(expr: &AnyJsExpression) -> Option<()> {
_ => None,
}
}

fn is_non_null_literal_type(ty: &AnyTsType) -> bool {
matches!(
ty,
AnyTsType::TsBooleanLiteralType(_)
| AnyTsType::TsBigintLiteralType(_)
| AnyTsType::TsNumberLiteralType(_)
| AnyTsType::TsStringLiteralType(_)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@ const x: false = !1;
const x: true = true;
const x: true = !false;
const x: true = !0;
const x: null = null;
const x: 1 = +1;
const x: -1 = -1;
const x: 1e-5 = 1e-5;
const x: RegExp = /a/;
const x: "str" = "str";
const x: "str" = `str`; // constant template string
const x: "str2" = `str${f()}`;
const x: undefined = void f();

class X {
readonly x: 1 = 1;
Expand Down
Loading

0 comments on commit 80a7987

Please sign in to comment.