diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index 8ec31b02f90cf..ec19595e5b184 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -100,6 +100,7 @@ mod eslint { mod typescript { pub mod adjacent_overload_signatures; + pub mod array_type; pub mod ban_ts_comment; pub mod ban_types; pub mod no_duplicate_enum_values; @@ -389,6 +390,7 @@ oxc_macros::declare_all_lint_rules! { eslint::use_isnan, eslint::valid_typeof, typescript::adjacent_overload_signatures, + typescript::array_type, typescript::ban_ts_comment, typescript::ban_types, typescript::no_duplicate_enum_values, diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs new file mode 100644 index 0000000000000..4d6cbcccf1011 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -0,0 +1,1648 @@ +use oxc_ast::{ + ast::{TSType, TSTypeName, TSTypeOperator, TSTypeReference}, + AstKind, +}; +use oxc_diagnostics::{ + miette::{self, Diagnostic}, + thiserror::{self, Error}, +}; +use oxc_macros::declare_oxc_lint; +use oxc_semantic::AstNode; +use oxc_span::Span; + +use crate::{context::LintContext, fixer::Fix, rule::Rule}; + +#[derive(Debug, Default, Clone)] +pub struct ArrayType(Box); + +declare_oxc_lint!( + /// ### What it does + /// Require consistently using either `T[]` or `Array` for arrays. + /// + /// ### Why is this bad? + /// Using the `Array` type directly is not idiomatic. Instead, use the array type `T[]` or `Array`. + /// + /// ### Example + /// ```typescript + /// const arr: Array = new Array(); + /// const arr: number[] = new Array(); + /// ``` + ArrayType, + style, +); + +#[derive(Debug, Diagnostic, Error)] +pub enum ArrayTypeDiagnostic { + #[error("Array type using '{0}{2}[]' is forbidden. Use '{1}<{2}>' instead.")] + #[diagnostic(severity(warning))] + // readonlyPrefix className type + Generic(String, String, String, #[label] Span), + + #[error( + "Array type using '{0}{2}[]' is forbidden for non-simple types. Use '{1}<{2}>' instead." + )] + #[diagnostic(severity(warning))] + // readonlyPrefix className type + GenericSimple(String, String, String, #[label] Span), + + #[error("Array type using '{1}<{2}>' is forbidden. Use '{0}{2}[]' instead.")] + #[diagnostic(severity(warning))] + // readonlyPrefix className type + Array(String, String, String, #[label] Span), + + #[error("Array type using '{1}<{2}>' is forbidden for simple types. Use '{0}{2}[]' instead.")] + #[diagnostic(severity(warning))] + // readonlyPrefix className type + ArraySimple(String, String, String, #[label] Span), +} + +#[derive(Debug, Default, Clone)] +pub struct ArrayTypeConfig { + // The array type expected for mutable cases. + default: ArrayOption, + // The array type expected for readonly cases. If omitted, the value for `default` will be used. + readonly: Option, +} + +impl std::ops::Deref for ArrayType { + type Target = ArrayTypeConfig; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[derive(Debug, Default, Clone)] +pub enum ArrayOption { + #[default] + Array, + ArraySimple, + Generic, +} + +impl Rule for ArrayType { + fn from_configuration(value: serde_json::Value) -> Self { + Self(Box::new(ArrayTypeConfig { + default: value + .get(0) + .and_then(|v| v.get("default")) + .and_then(serde_json::Value::as_str) + .map_or_else( + || ArrayOption::Array, + |s| match s { + "array" => ArrayOption::Array, + "generic" => ArrayOption::Generic, + _ => ArrayOption::ArraySimple, + }, + ), + readonly: value + .get(0) + .and_then(|v| v.get("readonly")) + .and_then(serde_json::Value::as_str) + .map_or_else( + || None, + |s| match s { + "array" => Some(ArrayOption::Array), + "generic" => Some(ArrayOption::Generic), + _ => Some(ArrayOption::ArraySimple), + }, + ), + })) + } + + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { + let default_config = &self.default; + let readonly_config: &ArrayOption = + &self.readonly.clone().unwrap_or_else(|| default_config.clone()); + + match node.kind() { + AstKind::TSTypeAnnotation(ts_type_annotation) => { + check(&ts_type_annotation.type_annotation, default_config, readonly_config, ctx); + } + // for example: type barUnion = (string | number | boolean)[]; + AstKind::TSTypeAliasDeclaration(ts_alias_annotation) => { + check(&ts_alias_annotation.type_annotation, default_config, readonly_config, ctx); + } + // for example: let ya = [[1, '2']] as [number, string][]; + AstKind::TSAsExpression(ts_as_expression) => { + check(&ts_as_expression.type_annotation, default_config, readonly_config, ctx); + } + _ => {} + } + } +} + +fn check( + type_annotation: &TSType, + default_config: &ArrayOption, + readonly_config: &ArrayOption, + ctx: &LintContext, +) { + if let TSType::TSArrayType(array_type) = &type_annotation { + check_and_report_error_generic( + default_config, + array_type.span, + &array_type.element_type, + ctx, + false, + ); + } + + if let TSType::TSTypeOperatorType(ts_operator_type) = &type_annotation { + if matches!(&ts_operator_type.operator, TSTypeOperator::Readonly) { + if let TSType::TSArrayType(array_type) = &ts_operator_type.type_annotation { + check_and_report_error_generic( + readonly_config, + ts_operator_type.span, + &array_type.element_type, + ctx, + true, + ); + } + } + } + + if let TSType::TSTypeReference(ts_type_reference) = &type_annotation { + check_and_report_error_array(default_config, readonly_config, ts_type_reference, ctx); + } +} + +fn type_needs_parentheses(type_param: &TSType) -> bool { + match type_param { + TSType::TSTypeReference(node) => { + if let TSTypeName::IdentifierReference(identifier_reference) = &node.type_name { + return identifier_reference.name.as_str() == "ReadonlyArray"; + } + true + } + TSType::TSUnionType(_) + | TSType::TSFunctionType(_) + | TSType::TSIntersectionType(_) + | TSType::TSTypeOperatorType(_) + | TSType::TSInferType(_) + | TSType::TSConstructorType(_) => true, + _ => false, + } +} + +fn check_and_report_error_generic( + config: &ArrayOption, + type_reference_span: Span, + type_param: &TSType, + ctx: &LintContext, + is_readonly: bool, +) { + if matches!(config, ArrayOption::Array) { + return; + } + if matches!(config, ArrayOption::ArraySimple) && is_simple_type(type_param) { + return; + } + let source_text = ctx.source_text().to_string(); + + let readonly_prefix = if is_readonly { "readonly " } else { "" }; + let class_name = if is_readonly { "ReadonlyArray" } else { "Array" }; + let message_type = get_message_type(type_param, &source_text); + + let diagnostic = match config { + ArrayOption::Generic => ArrayTypeDiagnostic::Generic( + readonly_prefix.to_string(), + class_name.to_string(), + message_type.to_string(), + type_reference_span, + ), + _ => ArrayTypeDiagnostic::GenericSimple( + readonly_prefix.to_string(), + class_name.to_string(), + message_type.to_string(), + type_reference_span, + ), + }; + let element_type_span = get_ts_element_type_span(type_param); + let Some(element_type_span) = element_type_span else { return }; + + ctx.diagnostic_with_fix(diagnostic, || { + let type_text = + &source_text[element_type_span.start as usize..element_type_span.end as usize]; + let array_type_identifier = if is_readonly { "ReadonlyArray" } else { "Array" }; + + Fix::new( + array_type_identifier.to_string() + "<" + type_text + ">", + Span { start: type_reference_span.start, end: type_reference_span.end }, + ) + }); +} + +fn check_and_report_error_array( + default_config: &ArrayOption, + readonly_config: &ArrayOption, + ts_type_reference: &TSTypeReference, + ctx: &LintContext, +) { + let TSTypeName::IdentifierReference(ident_ref_type_name) = &ts_type_reference.type_name else { + return; + }; + + if ident_ref_type_name.name.as_str() != "ReadonlyArray" + && ident_ref_type_name.name.as_str() != "Array" + { + return; + } + let is_readonly_array_type = ident_ref_type_name.name == "ReadonlyArray"; + let config = if is_readonly_array_type { readonly_config } else { default_config }; + if matches!(config, ArrayOption::Generic) { + return; + } + let readonly_prefix: &str = if is_readonly_array_type { "readonly " } else { "" }; + let class_name = if is_readonly_array_type { "ReadonlyArray" } else { "Array" }; + let type_params = &ts_type_reference.type_parameters; + + if type_params.is_none() || type_params.as_ref().unwrap().params.len() == 0 { + let diagnostic = match config { + ArrayOption::Array => ArrayTypeDiagnostic::Array( + readonly_prefix.to_string(), + class_name.to_string(), + "any".to_string(), + ts_type_reference.span, + ), + _ => ArrayTypeDiagnostic::ArraySimple( + readonly_prefix.to_string(), + ident_ref_type_name.name.to_string(), + "any".to_string(), + ts_type_reference.span, + ), + }; + ctx.diagnostic_with_fix(diagnostic, || { + Fix::new(readonly_prefix.to_string() + "any[]", ts_type_reference.span) + }); + return; + } + if type_params.as_ref().unwrap().params.len() != 1 { + return; + } + let first_type_param = type_params.as_ref().unwrap().params.first().unwrap(); + if matches!(config, ArrayOption::ArraySimple) && !is_simple_type(first_type_param) { + return; + } + + let type_parens = type_needs_parentheses(first_type_param); + // TODO: support example: type Foo = ReadonlyArray[]; -> type Foo = (readonly object[])[]; + // let mut parent_parens: bool = readonly_prefix != ""; + // if let Some(parent) = ctx.nodes().parent_node(node.id()) { + // if let AstKind::TSTypeAnnotation(parent_node) = parent.kind() {} + // } else { + // parent_parens = false + // }; + let parent_parens = false; + + let element_type_span = get_ts_element_type_span(first_type_param); + let Some(element_type_span) = element_type_span else { return }; + + let type_text = + &ctx.source_text()[element_type_span.start as usize..element_type_span.end as usize]; + + let mut start = String::from(if parent_parens { "(" } else { "" }); + start.push_str(readonly_prefix); + start.push_str(if type_parens { "(" } else { "" }); + + let mut end = String::from(if type_parens { ")" } else { "" }); + end.push_str("[]"); + end.push_str(if parent_parens { ")" } else { "" }); + + let message_type = get_message_type(first_type_param, ctx.source_text()); + let diagnostic = match config { + ArrayOption::Array => ArrayTypeDiagnostic::Array( + readonly_prefix.to_string(), + class_name.to_string(), + message_type.to_string(), + ts_type_reference.span, + ), + _ => ArrayTypeDiagnostic::ArraySimple( + readonly_prefix.to_string(), + ident_ref_type_name.name.to_string(), + message_type.to_string(), + ts_type_reference.span, + ), + }; + ctx.diagnostic_with_fix(diagnostic, || { + Fix::new(start + type_text + end.as_str(), ts_type_reference.span) + }); +} + +// Check whatever node can be considered as simple type +fn is_simple_type(ts_type: &TSType) -> bool { + match ts_type { + TSType::TSAnyKeyword(_) + | TSType::TSBooleanKeyword(_) + | TSType::TSNeverKeyword(_) + | TSType::TSNumberKeyword(_) + | TSType::TSBigIntKeyword(_) + | TSType::TSObjectKeyword(_) + | TSType::TSStringKeyword(_) + | TSType::TSSymbolKeyword(_) + | TSType::TSUnknownKeyword(_) + | TSType::TSVoidKeyword(_) + | TSType::TSNullKeyword(_) + | TSType::TSArrayType(_) + | TSType::TSUndefinedKeyword(_) + | TSType::TSQualifiedName(_) + | TSType::TSThisKeyword(_) => true, + TSType::TSTypeReference(node) => { + let type_name = TSTypeName::get_first_name(&node.type_name); + if type_name.name.as_str() == "Array" { + if node.type_parameters.is_none() { + return true; + } + if node.type_parameters.as_ref().unwrap().params.len() == 1 { + return is_simple_type( + node.type_parameters.as_ref().unwrap().params.first().unwrap(), + ); + } + } else { + if node.type_parameters.is_some() { + return false; + } + if let TSTypeName::IdentifierReference(_) = &node.type_name { + return true; + } + return false; + } + false + } + _ => false, + } +} + +// Get the type name from the type node. for example: `Array` -> `string` +fn get_message_type<'a>(type_param: &'a TSType, source_text: &'a str) -> &'a str { + if is_simple_type(type_param) { + let element_type_span = get_ts_element_type_span(type_param); + let Some(element_type_span) = element_type_span else { return "T" }; + return &source_text[element_type_span.start as usize..element_type_span.end as usize]; + } + "T" +} + +fn get_ts_element_type_span(ts_type: &TSType) -> Option { + match ts_type { + TSType::TSAnyKeyword(t) => Some(t.span), + TSType::TSNumberKeyword(t) => Some(t.span), + TSType::TSStringKeyword(t) => Some(t.span), + TSType::TSBigIntKeyword(t) => Some(t.span), + TSType::TSBooleanKeyword(t) => Some(t.span), + TSType::TSNeverKeyword(t) => Some(t.span), + TSType::TSObjectKeyword(t) => Some(t.span), + TSType::TSSymbolKeyword(t) => Some(t.span), + TSType::TSUnknownKeyword(t) => Some(t.span), + TSType::TSVoidKeyword(t) => Some(t.span), + TSType::TSNullKeyword(t) => Some(t.span), + TSType::TSThisKeyword(t) => Some(t.span), + TSType::TSUndefinedKeyword(t) => Some(t.span), + + TSType::TSArrayType(t) => Some(t.span), + TSType::TSConditionalType(t) => Some(t.span), + TSType::TSConstructorType(t) => Some(t.span), + TSType::TSFunctionType(t) => Some(t.span), + TSType::TSImportType(t) => Some(t.span), + TSType::TSIndexedAccessType(t) => Some(t.span), + TSType::TSInferType(t) => Some(t.span), + TSType::TSIntersectionType(t) => Some(t.span), + TSType::TSLiteralType(t) => Some(t.span), + TSType::TSMappedType(t) => Some(t.span), + TSType::TSQualifiedName(t) => Some(t.span), + TSType::TSTemplateLiteralType(t) => Some(t.span), + TSType::TSTupleType(t) => Some(t.span), + TSType::TSTypeLiteral(t) => Some(t.span), + TSType::TSTypeOperatorType(t) => Some(t.span), + TSType::TSTypePredicate(t) => Some(t.span), + TSType::TSTypeQuery(t) => Some(t.span), + TSType::TSTypeReference(t) => Some(t.span), + TSType::TSUnionType(t) => Some(t.span), + + _ => None, + } +} + +#[test] +fn test() { + use crate::tester::Tester; + + let pass: Vec<(&str, Option)> = vec![ + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"generic"}]))), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: readonly bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: readonly (string | bigint)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: readonly bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ("let a = new Array();", Some(serde_json::json!([{"default":"array"}]))), + ("let a: { foo: Bar[] }[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ( + "function foo(a: Array): Array {}", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let yy: number[][] = [[4, 5], [6]];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "function fooFunction(foo: Array>) { + return foo.map(e => e.foo); + }", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " + function bazFunction(baz: Arr>) { + return baz.map(e => e.baz); + } + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let fooVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type fooUnion = Array;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type fooIntersection = Array;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " + namespace fooName { + type BarType = { bar: string }; + type BazType = Arr; + } + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " + interface FooInterface { + '.bar': { baz: string[] }; + } + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ("let yy: number[][] = [[4, 5], [6]];", Some(serde_json::json!([{"default":"array"}]))), + ( + "let ya = [[1, '2']] as [number, string][];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + " + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "function bazFunction(baz: Arr>) { + return baz.map(e => e.baz); + }", + Some(serde_json::json!([{"default":"array"}])), + ), + ("let barVar: ((c: number) => number)[];", Some(serde_json::json!([{"default":"array"}]))), + ( + "type barUnion = (string | number | boolean)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type barIntersection = (string & number)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + " + interface FooInterface { + '.bar': { baz: string[] }; + }", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type Unwrap = T extends (infer E)[] ? E : T;", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let xx: Array> = [[1, 2], [3]];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ("type Arr = Array;", Some(serde_json::json!([{"default":"generic"}]))), + ( + "function fooFunction(foo: Array>) { return foo.map(e => e.foo); }", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "function bazFunction(baz: Arr>) { return baz.map(e => e.baz) }", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let fooVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type fooUnion = Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type fooIntersection = Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type Unwrap = T extends Array ? E : T;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: ReadonlyArray = [[]];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly Array[] = [[]];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ]; + + let fail = vec![ + ("let a: Array = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: ReadonlyArray = [];", Some(serde_json::json!([{"default":"array"}]))), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ("let a: Array = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ("let a: number[] = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: (string | number)[] = [];", Some(serde_json::json!([{"default":"generic"}]))), + ("let a: readonly number[] = [];", Some(serde_json::json!([{"default":"generic"}]))), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | bigint)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | bigint)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly (string | bigint)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ("let a: { foo: Array }[] = [];", Some(serde_json::json!([{"default":"array"}]))), + ("let a: Array<{ foo: Bar[] }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + // ("let a: Array<{ foo: Foo | Bar[] }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + ( + "function foo(a: Array): Array {}", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let x: Array = [undefined] as undefined[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let y: string[] = >['2'];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ("let z: Array = [3, '4'];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let ya = [[1, '2']] as [number, string][];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ("type Arr = Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + " + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + xyz: this[]; + } + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let barVar: ((c: number) => number)[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type barUnion = (string | number | boolean)[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type barIntersection = (string & number)[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + // ("let v: Array = [{ bar: 'bar' }];", Some(serde_json::json!([{"default":"array-simple"}]))), + // ("let w: fooName.BazType[] = [['baz']];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let x: Array = [undefined] as undefined[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ("let y: string[] = >['2'];", Some(serde_json::json!([{"default":"array"}]))), + ("let z: Array = [3, '4'];", Some(serde_json::json!([{"default":"array"}]))), + ("type Arr = Array;", Some(serde_json::json!([{"default":"array"}]))), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"array"}]))), + ( + " + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + } + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + " + function fooFunction(foo: Array>) { + return foo.map(e => e.foo); + } + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let fooVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type fooUnion = Array;", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type fooIntersection = Array;", + Some(serde_json::json!([{"default":"array"}])), + ), + ("let x: Array;", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array<>;", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array;", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array<>;", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let x: Array = [1] as number[];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let y: string[] = >['2'];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let ya = [[1, '2']] as [number, string][];", + Some(serde_json::json!([{"default":"generic"}])), + ), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"generic"}]))), + ( + " + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + } + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + " + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let barVar: ((c: number) => number)[];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type barUnion = (string | number | boolean)[];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type barIntersection = (string & number)[];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + " + interface FooInterface { + '.bar': { baz: string[] }; + } + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + // ("type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"array"}]))), + // ("type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), + // ("type Foo = ReadonlyArray[];", Some(serde_json::json!([{"default":"array"}]))), + ( + "const foo: Array void> = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "const foo: ReadonlyArray void> = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ]; + + let fix: Vec<(&str, &str, Option)> = vec![ + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: Array = [];", + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: Array = [];", + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + "let a: (string | number)[] = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array","readonly":"generic"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array-simple"}])), + ), + ( + "let a: Array = [];", + "let a: number[] = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "let a: number[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let a: number[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly (string | number)[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array"}])), + ), + ( + "let a: number[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly number[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: number[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: (string | number)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly number[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly (string | number)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: bigint[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | bigint)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: ReadonlyArray = [];", + "let a: readonly bigint[] = [];", + Some(serde_json::json!([{"default":"generic","readonly":"array-simple"}])), + ), + ( + "let a: (string | bigint)[] = [];", + "let a: Array = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly bigint[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: readonly (string | bigint)[] = [];", + "let a: ReadonlyArray = [];", + Some(serde_json::json!([{"default":"generic","readonly":"generic"}])), + ), + ( + "let a: { foo: Array }[] = [];", + "let a: { foo: Bar[] }[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let a: Array<{ foo: Bar[] }> = [];", + "let a: Array<{ foo: Array }> = [];", + Some(serde_json::json!([{"default":"generic"}])), + ), + // ("let a: Array<{ foo: Foo | Bar[] }> = [];", "let a: Array<{ foo: Foo | Array }> = [];", Some(serde_json::json!([{"default":"generic"}]))), + ( + "function foo(a: Array): Array {}", + "function foo(a: Bar[]): Bar[] {}", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let x: Array = [undefined] as undefined[];", + "let x: undefined[] = [undefined] as undefined[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + // ("let y: string[] = >['2'];", "let y: string[] = ['2'];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let z: Array = [3, '4'];", + "let z: any[] = [3, '4'];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let ya = [[1, '2']] as [number, string][];", + "let ya = [[1, '2']] as Array<[number, string]>;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type Arr = Array;", + "type Arr = T[];", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", " + // // Ignore user defined aliases + // let yyyy: Arr>>> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + " + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + xyz: this[]; + } + ", + " + interface ArrayClass { + foo: T[]; + bar: T[]; + baz: Arr; + xyz: this[]; + } + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + " + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", + " + function barFunction(bar: Array>) { + return bar.map(e => e.bar); + } + ", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "let barVar: ((c: number) => number)[];", + "let barVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type barUnion = (string | number | boolean)[];", + "type barUnion = Array;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + ( + "type barIntersection = (string & number)[];", + "type barIntersection = Array;", + Some(serde_json::json!([{"default":"array-simple"}])), + ), + // ("let v: Array = [{ bar: 'bar' }];", "let v: fooName.BarType[] = [{ bar: 'bar' }];", Some(serde_json::json!([{"default":"array-simple"}]))), + // ("let w: fooName.BazType[] = [['baz']];", "let w: Array> = [['baz']];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let x: Array = [undefined] as undefined[];", + "let x: undefined[] = [undefined] as undefined[];", + Some(serde_json::json!([{"default":"array"}])), + ), + // ("let y: string[] = >['2'];", "let y: string[] = ['2'];", Some(serde_json::json!([{"default":"array"}]))), + ( + "let z: Array = [3, '4'];", + "let z: any[] = [3, '4'];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type Arr = Array;", + "type Arr = T[];", + Some(serde_json::json!([{"default":"array"}])), + ), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", " + // // Ignore user defined aliases + // let yyyy: Arr[][]> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"array"}]))), + ( + " + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + } + ", + " + interface ArrayClass { + foo: T[]; + bar: T[]; + baz: Arr; + } + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + " + function fooFunction(foo: Array>) { + return foo.map(e => e.foo); + } + ", + " + function fooFunction(foo: ArrayClass[]) { + return foo.map(e => e.foo); + } + ", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "let fooVar: Array<(c: number) => number>;", + "let fooVar: ((c: number) => number)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type fooUnion = Array;", + "type fooUnion = (string | number | boolean)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "type fooIntersection = Array;", + "type fooIntersection = (string & number)[];", + Some(serde_json::json!([{"default":"array"}])), + ), + ("let x: Array;", "let x: any[];", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array<>;", "let x: any[];", Some(serde_json::json!([{"default":"array"}]))), + ("let x: Array;", "let x: any[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ("let x: Array<>;", "let x: any[];", Some(serde_json::json!([{"default":"array-simple"}]))), + ( + "let x: Array = [1] as number[];", + "let x: Array = [1] as Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + // ("let y: string[] = >['2'];", "let y: Array = >['2'];", Some(serde_json::json!([{"default":"generic"}]))), + ( + "let ya = [[1, '2']] as [number, string][];", + "let ya = [[1, '2']] as Array<[number, string]>;", + Some(serde_json::json!([{"default":"generic"}])), + ), + // (" + // // Ignore user defined aliases + // let yyyy: Arr>[]> = [[[['2']]]]; + // ", " + // // Ignore user defined aliases + // let yyyy: Arr>>> = [[[['2']]]]; + // ", Some(serde_json::json!([{"default":"generic"}]))), + ( + " + interface ArrayClass { + foo: Array; + bar: T[]; + baz: Arr; + } + ", + " + interface ArrayClass { + foo: Array; + bar: Array; + baz: Arr; + } + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + " + function barFunction(bar: ArrayClass[]) { + return bar.map(e => e.bar); + } + ", + " + function barFunction(bar: Array>) { + return bar.map(e => e.bar); + } + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "let barVar: ((c: number) => number)[];", + "let barVar: Array<(c: number) => number>;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type barUnion = (string | number | boolean)[];", + "type barUnion = Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + "type barIntersection = (string & number)[];", + "type barIntersection = Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), + ( + " + interface FooInterface { + '.bar': { baz: string[] }; + } + ", + " + interface FooInterface { + '.bar': { baz: Array }; + } + ", + Some(serde_json::json!([{"default":"generic"}])), + ), + // ("type Unwrap = T extends Array ? E : T;", "type Unwrap = T extends (infer E)[] ? E : T;", Some(serde_json::json!([{"default":"array"}]))), + // ("type Unwrap = T extends (infer E)[] ? E : T;", "type Unwrap = T extends Array ? E : T;", Some(serde_json::json!([{"default":"generic"}]))), + // ("type Foo = ReadonlyArray[];", "type Foo = (readonly object[])[];", Some(serde_json::json!([{"default":"array"}]))), + ( + "const foo: Array void> = [];", + "const foo: (new (...args: any[]) => void)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ( + "const foo: ReadonlyArray void> = [];", + "const foo: readonly (new (...args: any[]) => void)[] = [];", + Some(serde_json::json!([{"default":"array"}])), + ), + ]; + + Tester::new(ArrayType::NAME, pass, fail).expect_fix(fix).test_and_snapshot(); +} diff --git a/crates/oxc_linter/src/snapshots/array_type.snap b/crates/oxc_linter/src/snapshots/array_type.snap new file mode 100644 index 0000000000000..7e4d0d0e22c7a --- /dev/null +++ b/crates/oxc_linter/src/snapshots/array_type.snap @@ -0,0 +1,569 @@ +--- +source: crates/oxc_linter/src/tester.rs +assertion_line: 150 +expression: array_type +--- + + ⚠ Array type using 'Array' is forbidden. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ────────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ────────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ────────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ────────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ────────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ────────────────────── + ╰──── + + ⚠ Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly number[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ────────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: Array = []; + · ───────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly number[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: number[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly number[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: number[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ────────────────────────────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: number[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: number[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | number)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly number[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | number)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'bigint[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: bigint[] = []; + · ──────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | bigint)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly bigint[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: ReadonlyArray = []; + · ───────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: (string | bigint)[] = []; + · ─────────────────── + ╰──── + + ⚠ Array type using 'readonly bigint[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly bigint[] = []; + · ───────────────── + ╰──── + + ⚠ Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.tsx:1:8] + 1 │ let a: readonly (string | bigint)[] = []; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'Bar[]' instead. + ╭─[array_type.tsx:1:15] + 1 │ let a: { foo: Array }[] = []; + · ────────── + ╰──── + + ⚠ Array type using 'Bar[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:21] + 1 │ let a: Array<{ foo: Bar[] }> = []; + · ───── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'Bar[]' instead. + ╭─[array_type.tsx:1:17] + 1 │ function foo(a: Array): Array {} + · ────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'Bar[]' instead. + ╭─[array_type.tsx:1:30] + 1 │ function foo(a: Array): Array {} + · ────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'undefined[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array = [undefined] as undefined[]; + · ──────────────── + ╰──── + + × Expected `<` but found `EOF` + ╭─[array_type.tsx:1:1] + 1 │ let y: string[] = >['2']; + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let z: Array = [3, '4']; + · ───── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:24] + 1 │ let ya = [[1, '2']] as [number, string][]; + · ────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'T[]' instead. + ╭─[array_type.tsx:1:15] + 1 │ type Arr = Array; + · ──────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'T[]' instead. + ╭─[array_type.tsx:3:14] + 2 │ interface ArrayClass { + 3 │ foo: Array; + · ──────── + 4 │ bar: T[]; + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:2:35] + 1 │ + 2 │ function barFunction(bar: ArrayClass[]) { + · ──────────────────── + 3 │ return bar.map(e => e.bar); + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:13] + 1 │ let barVar: ((c: number) => number)[]; + · ───────────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:17] + 1 │ type barUnion = (string | number | boolean)[]; + · ───────────────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. + ╭─[array_type.tsx:1:24] + 1 │ type barIntersection = (string & number)[]; + · ─────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'undefined[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array = [undefined] as undefined[]; + · ──────────────── + ╰──── + + × Expected `<` but found `EOF` + ╭─[array_type.tsx:1:1] + 1 │ let y: string[] = >['2']; + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let z: Array = [3, '4']; + · ───── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:15] + 1 │ type Arr = Array; + · ──────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:3:14] + 2 │ interface ArrayClass { + 3 │ foo: Array; + · ──────── + 4 │ bar: T[]; + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:2:35] + 1 │ + 2 │ function fooFunction(foo: Array>) { + · ───────────────────────── + 3 │ return foo.map(e => e.foo); + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:13] + 1 │ let fooVar: Array<(c: number) => number>; + · ──────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:17] + 1 │ type fooUnion = Array; + · ──────────────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:24] + 1 │ type fooIntersection = Array; + · ────────────────────── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array; + · ───── + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array<>; + · ─────── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array; + · ───── + ╰──── + + ⚠ Array type using 'Array' is forbidden for simple types. Use 'any[]' instead. + ╭─[array_type.tsx:1:8] + 1 │ let x: Array<>; + · ─────── + ╰──── + + ⚠ Array type using 'number[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:31] + 1 │ let x: Array = [1] as number[]; + · ──────── + ╰──── + + × Expected `<` but found `EOF` + ╭─[array_type.tsx:1:1] + 1 │ let y: string[] = >['2']; + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:24] + 1 │ let ya = [[1, '2']] as [number, string][]; + · ────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:4:14] + 3 │ foo: Array; + 4 │ bar: T[]; + · ─── + 5 │ baz: Arr; + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:2:35] + 1 │ + 2 │ function barFunction(bar: ArrayClass[]) { + · ──────────────────── + 3 │ return bar.map(e => e.bar); + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:13] + 1 │ let barVar: ((c: number) => number)[]; + · ───────────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:17] + 1 │ type barUnion = (string | number | boolean)[]; + · ───────────────────────────── + ╰──── + + ⚠ Array type using 'T[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:1:24] + 1 │ type barIntersection = (string & number)[]; + · ─────────────────── + ╰──── + + ⚠ Array type using 'string[]' is forbidden. Use 'Array' instead. + ╭─[array_type.tsx:3:24] + 2 │ interface FooInterface { + 3 │ '.bar': { baz: string[] }; + · ──────── + 4 │ } + ╰──── + + ⚠ Array type using 'Array' is forbidden. Use 'T[]' instead. + ╭─[array_type.tsx:1:12] + 1 │ const foo: Array void> = []; + · ─────────────────────────────────── + ╰──── + + ⚠ Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. + ╭─[array_type.tsx:1:12] + 1 │ const foo: ReadonlyArray void> = []; + · ─────────────────────────────────────────── + ╰──── +