From 35e18980dcb10c10c815bdd927de474c5e948349 Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Sun, 10 Sep 2023 00:28:50 -0400 Subject: [PATCH] feat(linter): add typescript/no-explicit-any (#881) Implements `no-explicit-any` from `typescript-eslint`. Replaces #519 since it appears abandoned. --- crates/oxc_linter/src/rules.rs | 2 + .../src/rules/typescript/no_explicit_any.rs | 643 ++++++++++++++++++ .../src/snapshots/no_explicit_any.snap | 304 +++++++++ 3 files changed, 949 insertions(+) create mode 100644 crates/oxc_linter/src/rules/typescript/no_explicit_any.rs create mode 100644 crates/oxc_linter/src/snapshots/no_explicit_any.snap diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index cfd4045a95fde..4bcdf9b34add7 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -85,6 +85,7 @@ mod typescript { pub mod consistent_type_exports; pub mod no_duplicate_enum_values; pub mod no_empty_interface; + pub mod no_explicit_any; pub mod no_extra_non_null_assertion; pub mod no_misused_new; pub mod no_namespace; @@ -182,6 +183,7 @@ oxc_macros::declare_all_lint_rules! { typescript::consistent_type_exports, typescript::no_duplicate_enum_values, typescript::no_empty_interface, + typescript::no_explicit_any, typescript::no_extra_non_null_assertion, typescript::no_non_null_asserted_optional_chain, typescript::no_unnecessary_type_constraint, diff --git a/crates/oxc_linter/src/rules/typescript/no_explicit_any.rs b/crates/oxc_linter/src/rules/typescript/no_explicit_any.rs new file mode 100644 index 0000000000000..a20e110fa794e --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_explicit_any.rs @@ -0,0 +1,643 @@ +use crate::Fix; +use oxc_ast::AstKind; +use oxc_diagnostics::{ + miette::{self, Diagnostic}, + thiserror::Error, +}; +use oxc_macros::declare_oxc_lint; +use oxc_span::Span; +use serde_json::Value; + +use crate::{context::LintContext, rule::Rule, AstNode}; + +#[derive(Debug, Error, Diagnostic)] +#[error("typescript-eslint(no-explicit-any): Unexpected any. Specify a different type.")] +#[diagnostic(severity(warning), help("Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct."))] +struct NoExplicitAnyDiagnostic(#[label] pub Span); + +#[derive(Debug, Default, Clone)] +pub struct NoExplicitAny { + /// Whether to enable auto-fixing in which the `any` type is converted to the `unknown` type. + /// + /// `false` by default. + fix_to_unknown: bool, + /// Whether to ignore rest parameter arrays. + /// + /// `false` by default. + ignore_rest_args: bool, +} + +declare_oxc_lint!( + /// ### What it does + /// + /// Disallows explicit use of the `any` type. + /// + /// ### Why is this bad? + /// + /// The `any` type in TypeScript is a dangerous "escape hatch" from the type system. Using + /// `any` disables many type checking rules and is generally best used only as a last resort or + /// when prototyping code. This rule reports on explicit uses of the `any` keyword as a type + /// annotation. + /// + /// > TypeScript's `--noImplicitAny` compiler option prevents an implied `any`, but doesn't + /// > prevent `any` from being explicitly used the way this rule does. + /// + /// ### Example + /// + /// Examples of **incorrect** code for this rule: + /// + /// ```typescript + /// const age: any = 'seventeen'; + /// const ages: any[] = ['seventeen'] + /// const ages: Array = ['seventeen']; + /// function greet(): any {} + /// function greet(): any[] {} + /// function greet(): Array {} + /// function greet(): Array> {} + /// function greet(param: Array): string {} + /// function greet(param: Array): Array {} + /// ``` + /// + /// Examples of **correct** code for this rule: + /// + /// ```typescript + /// const age: number = 17; + /// const ages: number[] = [17]; + /// const ages: Array = [17]; + /// function greet(): string {} + /// function greet(): string[] {} + /// function greet(): Array {} + /// function greet(): Array> {} + /// function greet(param: Array): string {} + /// function greet(param: Array): Array {} + /// ``` + /// + /// ## Options + /// + /// This rule accepts the following options: + /// + /// ### `ignoreRestArgs` + /// A boolean to specify if arrays from the rest operator are considered ok. `false` by + /// default. + /// + /// ### `fixToUnknown` + /// + /// Whether to enable auto-fixing in which the `any` type is converted to the `unknown` type. + /// `false` by default. + NoExplicitAny, + restriction +); + +impl Rule for NoExplicitAny { + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { + let AstKind::TSAnyKeyword(any) = node.kind() else { return }; + if self.ignore_rest_args && Self::is_in_rest(node, ctx) { + return; + } + + if self.fix_to_unknown { + ctx.diagnostic_with_fix(NoExplicitAnyDiagnostic(any.span), || { + Fix::new("unknown", any.span) + }); + } else { + ctx.diagnostic(NoExplicitAnyDiagnostic(any.span)); + } + } + + fn from_configuration(value: Value) -> Self { + let Some(cfg) = value.get(0) else { return Self::default() }; + let fix_to_unknown = cfg.get("fixToUnknown").and_then(Value::as_bool).unwrap_or(false); + let ignore_rest_args = cfg.get("ignoreRestArgs").and_then(Value::as_bool).unwrap_or(false); + + Self { fix_to_unknown, ignore_rest_args } + } +} + +impl NoExplicitAny { + fn is_in_rest<'a>(node: &AstNode<'a>, ctx: &LintContext<'a>) -> bool { + debug_assert!(matches!(node.kind(), AstKind::TSAnyKeyword(_))); + ctx.nodes() + .iter_parents(node.id()) + .any(|parent| matches!(parent.kind(), AstKind::RestElement(_))) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tester::Tester; + use serde_json::json; + + #[test] + fn test_simple() { + let pass = vec!["let x: number = 1"]; + let fail = vec!["let x: any = 1"]; + Tester::new_without_config(NoExplicitAny::NAME, pass, fail).test(); + } + + #[allow(clippy::too_many_lines)] + #[test] + fn test() { + let pass = vec![ + ("const number: number = 1;", None), + ("function greet(): string {}", None), + ("function greet(): Array {}", None), + ("function greet(): string[] {}", None), + ("function greet(): Array> {}", None), + ("function greet(): Array {}", None), + ("function greet(param: Array): Array {}", None), + ( + " + class Greeter { + message: string; + } + ", + None, + ), + ( + " + class Greeter { + message: Array; + } + ", + None, + ), + ( + " + class Greeter { + message: string[]; + } + ", + None, + ), + ( + " + class Greeter { + message: Array>; + } + ", + None, + ), + ( + " + class Greeter { + message: Array; + } + ", + None, + ), + ( + " + interface Greeter { + message: string; + } + ", + None, + ), + ( + " + interface Greeter { + message: Array; + } + ", + None, + ), + ( + " + interface Greeter { + message: string[]; + } + ", + None, + ), + ( + " + interface Greeter { + message: Array>; + } + ", + None, + ), + ( + " + interface Greeter { + message: Array; + } + ", + None, + ), + ( + " + type obj = { + message: string; + }; + ", + None, + ), + ( + " + type obj = { + message: Array; + }; + ", + None, + ), + ( + " + type obj = { + message: string[]; + }; + ", + None, + ), + ( + " + type obj = { + message: Array>; + }; + ", + None, + ), + ( + " + type obj = { + message: Array; + }; + ", + None, + ), + ( + " + type obj = { + message: string | number; + }; + ", + None, + ), + ( + " + type obj = { + message: string | Array; + }; + ", + None, + ), + ( + " + type obj = { + message: string | string[]; + }; + ", + None, + ), + ( + " + type obj = { + message: string | Array>; + }; + ", + None, + ), + ( + " + type obj = { + message: string & number; + }; + ", + None, + ), + ( + " + type obj = { + message: string & Array; + }; + ", + None, + ), + ( + " + type obj = { + message: string & string[]; + }; + ", + None, + ), + ( + " + type obj = { + message: string & Array>; + }; + ", + None, + ), + ( + " + function foo(a: number, ...rest: any[]): void { + return; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "function foo1(...args: any[]) {}", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "const bar1 = function (...args: any[]) {};", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "const baz1 = (...args: any[]) => {};", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "function foo2(...args: readonly any[]) {}", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "const bar2 = function (...args: readonly any[]) {};", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "const baz2 = (...args: readonly any[]) => {};", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "function foo3(...args: Array) {}", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "const bar3 = function (...args: Array) {};", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "const baz3 = (...args: Array) => {};", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "function foo4(...args: ReadonlyArray) {}", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "const bar4 = function (...args: ReadonlyArray) {};", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "const baz4 = (...args: ReadonlyArray) => {};", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + " + interface Qux1 { + (...args: any[]): void; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + " + interface Qux2 { + (...args: readonly any[]): void; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + " + interface Qux3 { + (...args: Array): void; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + " + interface Qux4 { + (...args: ReadonlyArray): void; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "function quux1(fn: (...args: any[]) => void): void {}", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "function quux2(fn: (...args: readonly any[]) => void): void {}", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "function quux3(fn: (...args: Array) => void): void {}", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "function quux4(fn: (...args: ReadonlyArray) => void): void {}", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "function quuz1(): (...args: any[]) => void {}", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "function quuz2(): (...args: readonly any[]) => void {}", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "function quuz3(): (...args: Array) => void {}", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "function quuz4(): (...args: ReadonlyArray) => void {}", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "type Fred1 = (...args: any[]) => void;", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "type Fred2 = (...args: readonly any[]) => void;", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "type Fred3 = (...args: Array) => void;", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "type Fred4 = (...args: ReadonlyArray) => void;", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "type Corge1 = new (...args: any[]) => void;", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "type Corge2 = new (...args: readonly any[]) => void;", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "type Corge3 = new (...args: Array) => void;", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "type Corge4 = new (...args: ReadonlyArray) => void;", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + " + interface Grault1 { + new (...args: any[]): void; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + " + interface Grault2 { + new (...args: readonly any[]): void; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + " + interface Grault3 { + new (...args: Array): void; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + " + interface Grault4 { + new (...args: ReadonlyArray): void; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + " + interface Garply1 { + f(...args: any[]): void; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + " + interface Garply2 { + f(...args: readonly any[]): void; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + " + interface Garply3 { + f(...args: Array): void; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + " + interface Garply4 { + f(...args: ReadonlyArray): void; + } + ", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "declare function waldo1(...args: any[]): void;", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "declare function waldo2(...args: readonly any[]): void;", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "declare function waldo3(...args: Array): void;", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ( + "declare function waldo4(...args: ReadonlyArray): void;", + Some(serde_json::json!([{ "ignoreRestArgs": true }])), + ), + ]; + + let fail = vec![ + ("const number: any = 1", None), + ("function generic(): any {}", None), + ("function generic(): Array", None), + ("function generic(): any[] {}", None), + ("function generic(param: Array): number { return 1 }", None), + ("function generic(param: any[]): number { return 1 }", None), + ("function generic(param: Array): Array", None), + ("function generic(): Array>", None), + ("function generic(param: Array): Array", None), + ("class Greeter { constructor(param: Array) {} }", None), + ("class Greeter { message: any }", None), + ("class Greeter { message: Array }", None), + ("class Greeter { message: any[] }", None), + ("class Greeter { message: Array> }", None), + ("interface Greeter { constructor(param: Array) {} }", None), + ("interface Greeter { message: any }", None), + ("interface Greeter { message: Array }", None), + ("interface Greeter { message: any[] }", None), + ("interface Greeter { message: Array> }", None), + ("type obj = { constructor(param: Array) {} }", None), + ("type obj = { message: any }", None), + ("type obj = { message: Array }", None), + ("type obj = { message: any[] }", None), + ("type obj = { message: Array> }", None), + ("type obj = { message: string | any }", None), + ("type obj = { message: string | Array }", None), + ("type obj = { message: string | Array }", None), + ("type obj = { message: string | Array> }", None), + ("type obj = { message: string & any }", None), + ("type obj = { message: string & any[] }", None), + ("type obj = { message: string & Array }", None), + ("type obj = { message: string & Array> }", None), + ("type obj = { message: string & Array }", None), + ("class Foo extends Bar {}", None), + ("abstract class Foo extends Bar {}", None), + ("function test>() {}", None), + ("const test = >() => {};", None), + ("function foo(a: number, ...rest: any[]): void { return; }", None), + ("type Any = any;", None), + // todo + // ( + // "function foo(...args: any) {}", + // Some(serde_json::json!([{ "ignoreRestArgs": true }])), + // ), + ]; + + let fix_options = Some(json!([{ "fixToUnknown": true }])); + let fixes = vec![ + ("let x: any = 1", "let x: unknown = 1", fix_options.clone()), + ("function foo(): any", "function foo(): unknown", fix_options.clone()), + ( + "function foo(args: any): void {}", + "function foo(args: unknown): void {}", + fix_options.clone(), + ), + ( + "function foo(args: any[]): void {}", + "function foo(args: unknown[]): void {}", + fix_options.clone(), + ), + ( + "function foo(...args: any[]): void {}", + "function foo(...args: unknown[]): void {}", + fix_options.clone(), + ), + ( + "function foo(args: Array): void {}", + "function foo(args: Array): void {}", + fix_options, + ), + // NOTE: no current way to check that fixes don't occur when `ignoreRestArgs` is + // `true`, since no fix technically occurs and `expect_fix()` panics without a fix. + ]; + Tester::new(NoExplicitAny::NAME, pass, fail).expect_fix(fixes).test_and_snapshot(); + } +} diff --git a/crates/oxc_linter/src/snapshots/no_explicit_any.snap b/crates/oxc_linter/src/snapshots/no_explicit_any.snap new file mode 100644 index 0000000000000..c114d7877234d --- /dev/null +++ b/crates/oxc_linter/src/snapshots/no_explicit_any.snap @@ -0,0 +1,304 @@ +--- +source: crates/oxc_linter/src/tester.rs +expression: no_explicit_any +--- + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ const number: any = 1 + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ function generic(): any {} + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ function generic(): Array + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ function generic(): any[] {} + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ function generic(param: Array): number { return 1 } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ function generic(param: any[]): number { return 1 } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ function generic(param: Array): Array + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ function generic(param: Array): Array + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ function generic(): Array> + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ function generic(param: Array): Array + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ function generic(param: Array): Array + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ class Greeter { constructor(param: Array) {} } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ class Greeter { message: any } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ class Greeter { message: Array } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ class Greeter { message: any[] } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ class Greeter { message: Array> } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + × Unexpected token + ╭─[no_explicit_any.tsx:1:1] + 1 │ interface Greeter { constructor(param: Array) {} } + · ─ + ╰──── + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ interface Greeter { message: any } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ interface Greeter { message: Array } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ interface Greeter { message: any[] } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ interface Greeter { message: Array> } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + × Unexpected token + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { constructor(param: Array) {} } + · ─ + ╰──── + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: any } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: Array } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: any[] } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: Array> } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: string | any } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: string | Array } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: string | Array } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: string | Array> } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: string & any } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: string & any[] } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: string & Array } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: string & Array> } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type obj = { message: string & Array } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ class Foo extends Bar {} + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ class Foo extends Bar {} + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ abstract class Foo extends Bar {} + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ abstract class Foo extends Bar {} + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ function test>() {} + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ const test = >() => {}; + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ function foo(a: number, ...rest: any[]): void { return; } + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + + ⚠ typescript-eslint(no-explicit-any): Unexpected any. Specify a different type. + ╭─[no_explicit_any.tsx:1:1] + 1 │ type Any = any; + · ─── + ╰──── + help: Use `unknown` instead, this will force you to explicitly, and safely, assert the type is correct. + +