mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
feat(linter): typescript/no-inferrable-types (#7438)
This commit is contained in:
parent
ac0d25c426
commit
2ac9f963df
4 changed files with 872 additions and 0 deletions
|
|
@ -40,6 +40,7 @@ xdescribe = "xdescribe"
|
|||
seeked = "seeked"
|
||||
labeledby = "labeledby"
|
||||
hashi = "hashi"
|
||||
inferrable = "inferrable"
|
||||
|
||||
[default.extend-identifiers]
|
||||
IIFEs = "IIFEs"
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ mod typescript {
|
|||
pub mod no_extra_non_null_assertion;
|
||||
pub mod no_extraneous_class;
|
||||
pub mod no_import_type_side_effects;
|
||||
pub mod no_inferrable_types;
|
||||
pub mod no_misused_new;
|
||||
pub mod no_namespace;
|
||||
pub mod no_non_null_asserted_nullish_coalescing;
|
||||
|
|
@ -851,6 +852,7 @@ oxc_macros::declare_all_lint_rules! {
|
|||
typescript::consistent_type_definitions,
|
||||
typescript::consistent_type_imports,
|
||||
typescript::explicit_function_return_type,
|
||||
typescript::no_inferrable_types,
|
||||
typescript::no_confusing_non_null_assertion,
|
||||
typescript::no_duplicate_enum_values,
|
||||
typescript::no_dynamic_delete,
|
||||
|
|
|
|||
518
crates/oxc_linter/src/rules/typescript/no_inferrable_types.rs
Normal file
518
crates/oxc_linter/src/rules/typescript/no_inferrable_types.rs
Normal file
|
|
@ -0,0 +1,518 @@
|
|||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
use oxc_ast::{
|
||||
ast::{
|
||||
BindingPatternKind, ChainElement, Expression, FormalParameter, TSLiteral, TSType,
|
||||
TSTypeAnnotation, TSTypeName, UnaryOperator,
|
||||
},
|
||||
AstKind,
|
||||
};
|
||||
use oxc_diagnostics::OxcDiagnostic;
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::GetSpan;
|
||||
use oxc_span::Span;
|
||||
|
||||
fn no_inferrable_types_diagnostic(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::warn("Type can be trivially inferred from the initializer")
|
||||
.with_help("Remove the type annotation")
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoInferrableTypes {
|
||||
ignore_parameters: bool,
|
||||
ignore_properties: bool,
|
||||
}
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
/// Disallow explicit type declarations for variables or parameters initialized to a number, string, or boolean
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// Explicitly typing variables or parameters that are initialized to a literal value is unnecessary because TypeScript can infer the type from the value.
|
||||
///
|
||||
/// ### Examples
|
||||
///
|
||||
/// Examples of **incorrect** code for this rule:
|
||||
/// ```ts
|
||||
/// const a: number = 5;
|
||||
/// const b: string = 'foo';
|
||||
/// const c: boolean = true;
|
||||
/// const fn = (a: number = 5, b: boolean = true, c: string = 'foo') => {};
|
||||
/// ```
|
||||
///
|
||||
/// Examples of **correct** code for this rule:
|
||||
/// ```ts
|
||||
/// const a = 5;
|
||||
/// const b = 'foo';
|
||||
/// const c = true;
|
||||
/// const fn = (a = 5, b = true, c = 'foo') => {};
|
||||
/// ```
|
||||
NoInferrableTypes,
|
||||
style,
|
||||
pending
|
||||
);
|
||||
|
||||
impl Rule for NoInferrableTypes {
|
||||
fn from_configuration(value: serde_json::Value) -> Self {
|
||||
use serde_json::Value;
|
||||
let Some(config) = value.get(0).and_then(Value::as_object) else {
|
||||
return Self::default();
|
||||
};
|
||||
Self {
|
||||
ignore_parameters: config
|
||||
.get("ignoreParameters")
|
||||
.and_then(Value::as_bool)
|
||||
.unwrap_or(false),
|
||||
ignore_properties: config
|
||||
.get("ignoreProperties")
|
||||
.and_then(Value::as_bool)
|
||||
.unwrap_or(false),
|
||||
}
|
||||
}
|
||||
|
||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
match node.kind() {
|
||||
AstKind::VariableDeclarator(variable_decl) => {
|
||||
if let (Some(init), Some(type_annotation)) =
|
||||
(&variable_decl.init, &variable_decl.id.type_annotation)
|
||||
{
|
||||
if is_inferrable_type(type_annotation, init) {
|
||||
ctx.diagnostic(no_inferrable_types_diagnostic(type_annotation.span()));
|
||||
}
|
||||
}
|
||||
}
|
||||
AstKind::Function(function) => {
|
||||
self.check_formal_parameters(&function.params.items, ctx);
|
||||
}
|
||||
AstKind::ArrowFunctionExpression(arrow_function_expression) => {
|
||||
self.check_formal_parameters(&arrow_function_expression.params.items, ctx);
|
||||
}
|
||||
AstKind::PropertyDefinition(property_definition) => {
|
||||
// We ignore `readonly` because of Microsoft/TypeScript#14416
|
||||
// Essentially a readonly property without a type
|
||||
// will result in its value being the type, leading to
|
||||
// compile errors if the type is stripped.
|
||||
if self.ignore_properties
|
||||
|| property_definition.readonly
|
||||
|| property_definition.optional
|
||||
{
|
||||
return;
|
||||
}
|
||||
if let (Some(init), Some(type_annotation)) =
|
||||
(&property_definition.value, &property_definition.type_annotation)
|
||||
{
|
||||
if is_inferrable_type(type_annotation, init) {
|
||||
ctx.diagnostic(no_inferrable_types_diagnostic(type_annotation.span()));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NoInferrableTypes {
|
||||
fn check_formal_parameters<'a>(
|
||||
&self,
|
||||
params: &oxc_allocator::Vec<'a, FormalParameter<'a>>,
|
||||
ctx: &LintContext<'a>,
|
||||
) {
|
||||
if self.ignore_parameters {
|
||||
return;
|
||||
}
|
||||
|
||||
for param in params {
|
||||
if let BindingPatternKind::AssignmentPattern(param_assignment_pat) = ¶m.pattern.kind
|
||||
{
|
||||
if let Some(type_annotation) = ¶m_assignment_pat.left.type_annotation {
|
||||
if is_inferrable_type(type_annotation, ¶m_assignment_pat.right) {
|
||||
ctx.diagnostic(no_inferrable_types_diagnostic(type_annotation.span()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_inferrable_type(type_annotation: &TSTypeAnnotation, init: &Expression) -> bool {
|
||||
match &type_annotation.type_annotation {
|
||||
TSType::TSLiteralType(ts_literal_type) => match &ts_literal_type.literal {
|
||||
TSLiteral::BooleanLiteral(_) => is_init_boolean(init),
|
||||
TSLiteral::NullLiteral(_) => is_init_null(init),
|
||||
TSLiteral::NumericLiteral(_) => is_init_number(init),
|
||||
TSLiteral::BigIntLiteral(_) => is_init_bigint(init),
|
||||
TSLiteral::StringLiteral(_) => is_init_string(init),
|
||||
TSLiteral::RegExpLiteral(_) => is_init_regexp(init),
|
||||
TSLiteral::TemplateLiteral(_) | TSLiteral::UnaryExpression(_) => false,
|
||||
},
|
||||
TSType::TSStringKeyword(_) => is_init_string(init),
|
||||
TSType::TSBigIntKeyword(_) => is_init_bigint(init),
|
||||
TSType::TSBooleanKeyword(_) => is_init_boolean(init),
|
||||
TSType::TSNumberKeyword(_) => is_init_number(init),
|
||||
TSType::TSNullKeyword(_) => is_init_null(init),
|
||||
TSType::TSSymbolKeyword(_) => {
|
||||
if is_chain_call_expression_with_name(init, "Symbol") {
|
||||
return true;
|
||||
}
|
||||
if let Expression::CallExpression(call_expr) = init.get_inner_expression() {
|
||||
call_expr.callee.get_identifier_reference().map_or(false, |id| id.name == "Symbol")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
TSType::TSTypeReference(type_reference) => {
|
||||
if let TSTypeName::IdentifierReference(ident) = &type_reference.type_name {
|
||||
if ident.name == "RegExp" {
|
||||
return is_init_regexp(init);
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
TSType::TSUndefinedKeyword(_) => match init.get_inner_expression() {
|
||||
Expression::Identifier(id) => id.name == "undefined",
|
||||
Expression::UnaryExpression(unary_expr) => {
|
||||
matches!(unary_expr.operator, UnaryOperator::Void)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_chain_call_expression_with_name(init: &Expression, name: &str) -> bool {
|
||||
if let Expression::ChainExpression(chain_expr) = init {
|
||||
if let ChainElement::CallExpression(call_expr) = &chain_expr.expression {
|
||||
return call_expr.callee.get_identifier_reference().map_or(false, |id| id.name == name);
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn is_init_bigint(init: &Expression) -> bool {
|
||||
let init = {
|
||||
let init = init.get_inner_expression();
|
||||
if let Expression::UnaryExpression(unary_expr) = init {
|
||||
if matches!(
|
||||
unary_expr.operator,
|
||||
UnaryOperator::UnaryPlus | UnaryOperator::UnaryNegation
|
||||
) {
|
||||
unary_expr.argument.get_inner_expression()
|
||||
} else {
|
||||
init
|
||||
}
|
||||
} else {
|
||||
init
|
||||
}
|
||||
};
|
||||
|
||||
if is_chain_call_expression_with_name(init, "BigInt") {
|
||||
return true;
|
||||
}
|
||||
|
||||
match init {
|
||||
Expression::CallExpression(call_expr) => {
|
||||
call_expr.callee.get_identifier_reference().map_or(false, |id| id.name == "BigInt")
|
||||
}
|
||||
Expression::BigIntLiteral(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_init_boolean(init: &Expression) -> bool {
|
||||
if is_chain_call_expression_with_name(init, "Boolean") {
|
||||
return true;
|
||||
}
|
||||
match init.get_inner_expression() {
|
||||
Expression::UnaryExpression(unary_expr) => {
|
||||
matches!(unary_expr.operator, UnaryOperator::LogicalNot)
|
||||
}
|
||||
Expression::CallExpression(call_expr) => {
|
||||
call_expr.callee.get_identifier_reference().map_or(false, |id| id.name == "Boolean")
|
||||
}
|
||||
Expression::BooleanLiteral(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_init_null(init: &Expression) -> bool {
|
||||
let init = init.get_inner_expression();
|
||||
matches!(init, Expression::NullLiteral(_))
|
||||
}
|
||||
|
||||
fn is_init_number(init: &Expression) -> bool {
|
||||
let init = {
|
||||
let init = init.get_inner_expression();
|
||||
if let Expression::UnaryExpression(unary_expr) = init {
|
||||
if matches!(
|
||||
unary_expr.operator,
|
||||
UnaryOperator::UnaryPlus | UnaryOperator::UnaryNegation
|
||||
) {
|
||||
unary_expr.argument.get_inner_expression()
|
||||
} else {
|
||||
init
|
||||
}
|
||||
} else {
|
||||
init
|
||||
}
|
||||
};
|
||||
if is_chain_call_expression_with_name(init, "Number") {
|
||||
return true;
|
||||
}
|
||||
match init {
|
||||
Expression::Identifier(id) => id.name == "Infinity" || id.name == "NaN",
|
||||
Expression::CallExpression(call_expr) => {
|
||||
call_expr.callee.get_identifier_reference().map_or(false, |id| id.name == "Number")
|
||||
}
|
||||
Expression::NumericLiteral(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
fn is_init_string(init: &Expression) -> bool {
|
||||
if is_chain_call_expression_with_name(init, "String") {
|
||||
return true;
|
||||
}
|
||||
match init {
|
||||
Expression::CallExpression(call_expr) => {
|
||||
call_expr.callee.get_identifier_reference().map_or(false, |id| id.name == "String")
|
||||
}
|
||||
Expression::StringLiteral(_) | Expression::TemplateLiteral(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
fn is_init_regexp(init: &Expression) -> bool {
|
||||
if is_chain_call_expression_with_name(init, "RegExp") {
|
||||
return true;
|
||||
}
|
||||
match init.get_inner_expression() {
|
||||
Expression::RegExpLiteral(_) => true,
|
||||
Expression::NewExpression(new_expr) => {
|
||||
if let Expression::Identifier(id) = new_expr.callee.get_inner_expression() {
|
||||
id.name == "RegExp"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
Expression::CallExpression(call_expr) => {
|
||||
if let Expression::Identifier(id) = call_expr.callee.get_inner_expression() {
|
||||
id.name == "RegExp"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
(r"const a = 10n", None),
|
||||
(r"const a = -10n", None),
|
||||
(r"const a = BigInt(10)", None),
|
||||
(r"const a = -BigInt(10)", None),
|
||||
(r"const a = BigInt?.(10)", None),
|
||||
(r"const a = -BigInt?.(10)", None),
|
||||
(r"const a = false", None),
|
||||
(r"const a = true", None),
|
||||
(r"const a = Boolean(null)", None),
|
||||
(r"const a = Boolean?.(null)", None),
|
||||
(r"const a = !0", None),
|
||||
(r"const a = 10", None),
|
||||
(r"const a = +10", None),
|
||||
(r"const a = -10", None),
|
||||
(r#"const a = Number("1")"#, None),
|
||||
(r#"const a = +Number("1")"#, None),
|
||||
(r#"const a = -Number("1")"#, None),
|
||||
(r#"const a = Number?.("1")"#, None),
|
||||
(r#"const a = +Number?.("1")"#, None),
|
||||
(r#"const a = -Number?.("1")"#, None),
|
||||
(r"const a = Infinity", None),
|
||||
(r"const a = +Infinity", None),
|
||||
(r"const a = -Infinity", None),
|
||||
(r"const a = NaN", None),
|
||||
(r"const a = +NaN", None),
|
||||
(r"const a = -NaN", None),
|
||||
(r"const a = null", None),
|
||||
(r"const a = /a/", None),
|
||||
(r#"const a = RegExp("a")"#, None),
|
||||
(r#"const a = RegExp?.("a")"#, None),
|
||||
(r#"const a = new RegExp("a")"#, None),
|
||||
(r#"const a = "str""#, None),
|
||||
(r"const a = 'str'", None),
|
||||
(r"const a = `str`", None),
|
||||
(r"const a = String(1)", None),
|
||||
(r"const a = String?.(1)", None),
|
||||
(r#"const a = Symbol("a")"#, None),
|
||||
(r#"const a = Symbol?.("a")"#, None),
|
||||
(r"const a = undefined", None),
|
||||
(r"const a = void someValue", None),
|
||||
("const fn = (a = 5, b = true, c = 'foo') => {};", None),
|
||||
("const fn = function (a = 5, b = true, c = 'foo') {};", None),
|
||||
("function fn(a = 5, b = true, c = 'foo') {}", None),
|
||||
("function fn(a: number, b: boolean, c: string) {}", None),
|
||||
(
|
||||
"
|
||||
class Foo {
|
||||
a = 5;
|
||||
b = true;
|
||||
c = 'foo';
|
||||
}",
|
||||
None,
|
||||
),
|
||||
("class Foo { readonly a: number = 5; }", None),
|
||||
("const a: any = 5;", None),
|
||||
("const fn = function (a: any = 5, b: any = true, c: any = 'foo') {};", None),
|
||||
(
|
||||
"const fn = (a: number = 5, b: boolean = true, c: string = 'foo') => {};",
|
||||
Some(serde_json::json!([{ "ignoreParameters": true }])),
|
||||
),
|
||||
(
|
||||
"function fn(a: number = 5, b: boolean = true, c: string = 'foo') {}",
|
||||
Some(serde_json::json!([{ "ignoreParameters": true }])),
|
||||
),
|
||||
(
|
||||
"const fn = function (a: number = 5, b: boolean = true, c: string = 'foo') {};",
|
||||
Some(serde_json::json!([{ "ignoreParameters": true }])),
|
||||
),
|
||||
(
|
||||
"
|
||||
class Foo {
|
||||
a: number = 5;
|
||||
b: boolean = true;
|
||||
c: string = 'foo';
|
||||
}",
|
||||
Some(serde_json::json!([{ "ignoreProperties": true }])),
|
||||
),
|
||||
(
|
||||
"
|
||||
class Foo {
|
||||
a?: number = 5;
|
||||
b?: boolean = true;
|
||||
c?: string = 'foo';
|
||||
}",
|
||||
None,
|
||||
),
|
||||
("class Foo { constructor(public a = true) {} }", None),
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
(r"const a: bigint = 10n", None),
|
||||
(r"const a: bigint = -10n", None),
|
||||
(r"const a: bigint = BigInt(10)", None),
|
||||
(r"const a: bigint = -BigInt(10)", None),
|
||||
(r"const a: bigint = BigInt?.(10)", None),
|
||||
(r"const a: bigint = -BigInt?.(10)", None),
|
||||
(r"const a: boolean = false", None),
|
||||
(r"const a: boolean = true", None),
|
||||
(r"const a: boolean = Boolean(null)", None),
|
||||
(r"const a: boolean = Boolean?.(null)", None),
|
||||
(r"const a: boolean = !0", None),
|
||||
(r"const a: number = 10", None),
|
||||
(r"const a: number = +10", None),
|
||||
(r"const a: number = -10", None),
|
||||
(r#"const a: number = Number("1")"#, None),
|
||||
(r#"const a: number = +Number("1")"#, None),
|
||||
(r#"const a: number = -Number("1")"#, None),
|
||||
(r#"const a: number = Number?.("1")"#, None),
|
||||
(r#"const a: number = +Number?.("1")"#, None),
|
||||
(r#"const a: number = -Number?.("1")"#, None),
|
||||
(r"const a: number = Infinity", None),
|
||||
(r"const a: number = +Infinity", None),
|
||||
(r"const a: number = -Infinity", None),
|
||||
(r"const a: number = NaN", None),
|
||||
(r"const a: number = +NaN", None),
|
||||
(r"const a: number = -NaN", None),
|
||||
(r"const a: null = null", None),
|
||||
(r"const a: RegExp = /a/", None),
|
||||
(r#"const a: RegExp = RegExp("a")"#, None),
|
||||
(r#"const a: RegExp = RegExp?.("a")"#, None),
|
||||
(r#"const a: RegExp = new RegExp("a")"#, None),
|
||||
(r#"const a: string = "str""#, None),
|
||||
(r"const a: string = 'str'", None),
|
||||
(r"const a: string = `str`", None),
|
||||
(r"const a: string = String(1)", None),
|
||||
(r"const a: string = String?.(1)", None),
|
||||
(r#"const a: symbol = Symbol("a")"#, None),
|
||||
(r#"const a: symbol = Symbol?.("a")"#, None),
|
||||
(r"const a: undefined = undefined", None),
|
||||
(r"const a: undefined = void someValue", None),
|
||||
(
|
||||
"const fn = (a?: number = 5) => {};",
|
||||
Some(serde_json::json!([{ "ignoreParameters": false }])),
|
||||
),
|
||||
("class A { a!: number = 1; }", Some(serde_json::json!([{ "ignoreProperties": false }]))),
|
||||
(
|
||||
"const fn = (a: number = 5, b: boolean = true, c: string = 'foo') => {};",
|
||||
Some(serde_json::json!([{ "ignoreParameters": false, "ignoreProperties": false }])),
|
||||
),
|
||||
(
|
||||
"class Foo {
|
||||
a: number = 5;
|
||||
b: boolean = true;
|
||||
c: string = 'foo';
|
||||
}",
|
||||
Some(serde_json::json!([{ "ignoreParameters": false, "ignoreProperties": false }])),
|
||||
),
|
||||
(
|
||||
"class Foo { constructor(public a: boolean = true) {} }",
|
||||
Some(serde_json::json!([{ "ignoreParameters": false, "ignoreProperties": false }])),
|
||||
),
|
||||
];
|
||||
|
||||
let _fix = vec![
|
||||
(
|
||||
"const fn = (a?: number = 5) => {};",
|
||||
"const fn = (a = 5) => {};",
|
||||
Some(serde_json::json!([{ "ignoreParameters": false, }, ])),
|
||||
),
|
||||
(
|
||||
"
|
||||
class A {
|
||||
a!: number = 1;
|
||||
}
|
||||
",
|
||||
"
|
||||
class A {
|
||||
a = 1;
|
||||
}
|
||||
",
|
||||
Some(serde_json::json!([{ "ignoreProperties": false, }, ])),
|
||||
),
|
||||
(
|
||||
"const fn = (a: number = 5, b: boolean = true, c: string = 'foo') => {};",
|
||||
"const fn = (a = 5, b = true, c = 'foo') => {};",
|
||||
Some(
|
||||
serde_json::json!([{ "ignoreParameters": false, "ignoreProperties": false, }, ]),
|
||||
),
|
||||
),
|
||||
(
|
||||
"
|
||||
class Foo {
|
||||
a: number = 5;
|
||||
b: boolean = true;
|
||||
c: string = 'foo';
|
||||
}",
|
||||
"class Foo {
|
||||
a = 5;
|
||||
b = true;
|
||||
c = 'foo';
|
||||
}",
|
||||
Some(
|
||||
serde_json::json!([{ "ignoreParameters": false, "ignoreProperties": false, }, ]),
|
||||
),
|
||||
),
|
||||
(
|
||||
"class Foo { constructor(public a: boolean = true) {} }",
|
||||
"class Foo { constructor(public a = true) {} } ",
|
||||
Some(serde_json::json!([{ "ignoreParameters": false, "ignoreProperties": false, }, ])),
|
||||
),
|
||||
];
|
||||
Tester::new(NoInferrableTypes::NAME, pass, fail)
|
||||
//.expect_fix(fix)
|
||||
.test_and_snapshot();
|
||||
}
|
||||
351
crates/oxc_linter/src/snapshots/no_inferrable_types.snap
Normal file
351
crates/oxc_linter/src/snapshots/no_inferrable_types.snap
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
---
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: bigint = 10n
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: bigint = -10n
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: bigint = BigInt(10)
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: bigint = -BigInt(10)
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: bigint = BigInt?.(10)
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: bigint = -BigInt?.(10)
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: boolean = false
|
||||
· ─────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: boolean = true
|
||||
· ─────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: boolean = Boolean(null)
|
||||
· ─────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: boolean = Boolean?.(null)
|
||||
· ─────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: boolean = !0
|
||||
· ─────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = 10
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = +10
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = -10
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = Number("1")
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = +Number("1")
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = -Number("1")
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = Number?.("1")
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = +Number?.("1")
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = -Number?.("1")
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = Infinity
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = +Infinity
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = -Infinity
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = NaN
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = +NaN
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: number = -NaN
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: null = null
|
||||
· ──────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: RegExp = /a/
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: RegExp = RegExp("a")
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: RegExp = RegExp?.("a")
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: RegExp = new RegExp("a")
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: string = "str"
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: string = 'str'
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: string = `str`
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: string = String(1)
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: string = String?.(1)
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: symbol = Symbol("a")
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: symbol = Symbol?.("a")
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: undefined = undefined
|
||||
· ───────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:8]
|
||||
1 │ const a: undefined = void someValue
|
||||
· ───────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:15]
|
||||
1 │ const fn = (a?: number = 5) => {};
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:13]
|
||||
1 │ class A { a!: number = 1; }
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:14]
|
||||
1 │ const fn = (a: number = 5, b: boolean = true, c: string = 'foo') => {};
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:29]
|
||||
1 │ const fn = (a: number = 5, b: boolean = true, c: string = 'foo') => {};
|
||||
· ─────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:48]
|
||||
1 │ const fn = (a: number = 5, b: boolean = true, c: string = 'foo') => {};
|
||||
· ────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:2:16]
|
||||
1 │ class Foo {
|
||||
2 │ a: number = 5;
|
||||
· ────────
|
||||
3 │ b: boolean = true;
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:3:16]
|
||||
2 │ a: number = 5;
|
||||
3 │ b: boolean = true;
|
||||
· ─────────
|
||||
4 │ c: string = 'foo';
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:4:16]
|
||||
3 │ b: boolean = true;
|
||||
4 │ c: string = 'foo';
|
||||
· ────────
|
||||
5 │ }
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
|
||||
⚠ typescript-eslint(no-inferrable-types): Type can be trivially inferred from the initializer
|
||||
╭─[no_inferrable_types.tsx:1:33]
|
||||
1 │ class Foo { constructor(public a: boolean = true) {} }
|
||||
· ─────────
|
||||
╰────
|
||||
help: Remove the type annotation
|
||||
Loading…
Reference in a new issue