diff --git a/crates/oxc_linter/src/generated/rule_runner_impls.rs b/crates/oxc_linter/src/generated/rule_runner_impls.rs index 4035d8d931827..db4a4955210ab 100644 --- a/crates/oxc_linter/src/generated/rule_runner_impls.rs +++ b/crates/oxc_linter/src/generated/rule_runner_impls.rs @@ -2532,6 +2532,7 @@ impl RuleRunner for crate::rules::typescript::array_type::ArrayType { AstType::TSConditionalType, AstType::TSIndexedAccessType, AstType::TSMappedType, + AstType::TSSatisfiesExpression, AstType::TSTypeAliasDeclaration, AstType::TSTypeAnnotation, AstType::TSTypeParameterInstantiation, diff --git a/crates/oxc_linter/src/rules/typescript/array_type.rs b/crates/oxc_linter/src/rules/typescript/array_type.rs index 1e607fdeecf30..35eb6c68af698 100644 --- a/crates/oxc_linter/src/rules/typescript/array_type.rs +++ b/crates/oxc_linter/src/rules/typescript/array_type.rs @@ -179,6 +179,15 @@ impl Rule for ArrayType { ctx, ); } + // for example: const arr = [] as const satisfies readonly string[]; + AstKind::TSSatisfiesExpression(ts_satisfies_expression) => { + check( + &ts_satisfies_expression.type_annotation, + self.default_config(), + self.readonly_config(), + ctx, + ); + } AstKind::TSTypeReference(ts_type_reference) if outermost_paren_parent(node, ctx).is_some_and(|x| match x.kind() { AstKind::TSTypeAliasDeclaration(TSTypeAliasDeclaration { @@ -965,6 +974,15 @@ const instance = new MyClass(42);", "let z: readonly factories.User[] = [];", Some(serde_json::json!([{"readonly":"array-simple"}])), ), + // https://github.com/oxc-project/oxc/issues/16897 - satisfies expression + ( + "const arr = [] as const satisfies ReadonlyArray;", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "const arr = [] as const satisfies readonly string[];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), ]; let fail = vec![ @@ -1456,6 +1474,23 @@ export const test8 = testFn, number[]>([]);", "type MakeArrays = { [K in keyof T]: T[K][] };", Some(serde_json::json!([{"default":"generic"}])), ), + // https://github.com/oxc-project/oxc/issues/16897 - satisfies expression + ( + "const arr = [] as const satisfies readonly string[];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "const arr = [] as const satisfies readonly SupportedDomainName[];", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "const arr = [] as const satisfies ReadonlyArray;", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "const arr = [] as const satisfies string[];", + Some(serde_json::json!([{"default":"generic"}])), + ), ]; let fix: Vec<(&str, &str, Option)> = vec![ @@ -2103,6 +2138,27 @@ export const test9 = testFn>([]);", export const test9 = testFn([]);", Some(serde_json::json!([{"default":"array-simple"}])), ), + // https://github.com/oxc-project/oxc/issues/16897 - satisfies expression + ( + "const arr = [] as const satisfies readonly string[];", + "const arr = [] as const satisfies ReadonlyArray;", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "const arr = [] as const satisfies readonly SupportedDomainName[];", + "const arr = [] as const satisfies ReadonlyArray;", + Some(serde_json::json!([{"default":"array-simple","readonly":"generic"}])), + ), + ( + "const arr = [] as const satisfies ReadonlyArray;", + "const arr = [] as const satisfies readonly string[];", + Some(serde_json::json!([{"default":"array-simple","readonly":"array"}])), + ), + ( + "const arr = [] as const satisfies string[];", + "const arr = [] as const satisfies Array;", + Some(serde_json::json!([{"default":"generic"}])), + ), ]; Tester::new(ArrayType::NAME, ArrayType::PLUGIN, pass, fail) diff --git a/crates/oxc_linter/src/snapshots/typescript_array_type.snap b/crates/oxc_linter/src/snapshots/typescript_array_type.snap index e5681a421fdc8..5892aa73d225d 100644 --- a/crates/oxc_linter/src/snapshots/typescript_array_type.snap +++ b/crates/oxc_linter/src/snapshots/typescript_array_type.snap @@ -901,3 +901,31 @@ source: crates/oxc_linter/src/tester.rs · ────── ╰──── help: Replace `T[K][]` with `Array`. + + ⚠ typescript-eslint(array-type): Array type using 'readonly string[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.ts:1:35] + 1 │ const arr = [] as const satisfies readonly string[]; + · ───────────────── + ╰──── + help: Replace `readonly string[]` with `ReadonlyArray`. + + ⚠ typescript-eslint(array-type): Array type using 'readonly SupportedDomainName[]' is forbidden. Use 'ReadonlyArray' instead. + ╭─[array_type.ts:1:35] + 1 │ const arr = [] as const satisfies readonly SupportedDomainName[]; + · ────────────────────────────── + ╰──── + help: Replace `readonly SupportedDomainName[]` with `ReadonlyArray`. + + ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden. Use 'readonly string[]' instead. + ╭─[array_type.ts:1:35] + 1 │ const arr = [] as const satisfies ReadonlyArray; + · ───────────────────── + ╰──── + help: Replace `ReadonlyArray` with `readonly string[]`. + + ⚠ typescript-eslint(array-type): Array type using 'string[]' is forbidden. Use 'Array' instead. + ╭─[array_type.ts:1:35] + 1 │ const arr = [] as const satisfies string[]; + · ──────── + ╰──── + help: Replace `string[]` with `Array`.