diff --git a/packages/eslint-plugin/docs/rules/consistent-type-assertions.mdx b/packages/eslint-plugin/docs/rules/consistent-type-assertions.mdx
index 0b13d9df2677..9445bcf8b19b 100644
--- a/packages/eslint-plugin/docs/rules/consistent-type-assertions.mdx
+++ b/packages/eslint-plugin/docs/rules/consistent-type-assertions.mdx
@@ -115,6 +115,79 @@ const foo = ;
+### `arrayLiteralTypeAssertions`
+
+{/* insert option description */}
+
+Always prefer `const x: T[] = [ ... ];` to `const x = [ ... ] as T[];` (or similar with angle brackets).
+
+The compiler will warn for excess properties of elements with this syntax, but not missing _required_ fields of those objects.
+For example: `const x: {foo: number}[] = [{}];` will fail to compile, but `const x = [{}] as [{ foo: number }]` will succeed.
+
+The const assertion `const x = [1, 2, 3] as const`, introduced in TypeScript 3.4, is considered beneficial and is ignored by this option.
+
+Assertions to `any` are also ignored by this option.
+
+Examples of code for `{ assertionStyle: 'as', arrayLiteralTypeAssertions: 'never' }`:
+
+
+
+
+```ts option='{ "assertionStyle": "as", "arrayLiteralTypeAssertions": "never" }'
+const x = ['foo'] as T;
+
+function bar() {
+ return ['foo'] as T;
+}
+```
+
+
+
+
+```ts option='{ "assertionStyle": "as", "arrayLiteralTypeAssertions": "never" }'
+const x: T = ['foo'];
+const y = ['foo'] as any;
+const z = ['foo'] as unknown;
+
+function bar(): T {
+ return ['foo'];
+}
+```
+
+
+
+
+Examples of code for `{ assertionStyle: 'as', arrayLiteralTypeAssertions: 'allow-as-parameter' }`:
+
+
+
+
+```ts option='{ "assertionStyle": "as", "arrayLiteralTypeAssertions": "allow-as-parameter" }'
+const x = ['foo'] as T;
+
+function bar() {
+ return ['foo'] as T;
+}
+```
+
+
+
+
+```tsx option='{ "assertionStyle": "as", "arrayLiteralTypeAssertions": "allow-as-parameter" }'
+const x: T = ['foo'];
+const y = ['foo'] as any;
+const z = ['foo'] as unknown;
+bar(['foo'] as T);
+new Clazz(['foo'] as T);
+function bar() {
+ throw ['foo'] as Foo;
+}
+const foo = ;
+```
+
+
+
+
## When Not To Use It
If you do not want to enforce consistent type assertions.
diff --git a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts
index 8713405115d9..3f460f7d11da 100644
--- a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts
+++ b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts
@@ -18,19 +18,27 @@ export type MessageIds =
| 'angle-bracket'
| 'as'
| 'never'
+ | 'replaceArrayTypeAssertionWithAnnotation'
+ | 'replaceArrayTypeAssertionWithSatisfies'
| 'replaceObjectTypeAssertionWithAnnotation'
| 'replaceObjectTypeAssertionWithSatisfies'
+ | 'unexpectedArrayTypeAssertion'
| 'unexpectedObjectTypeAssertion';
type OptUnion =
| {
assertionStyle: 'angle-bracket' | 'as';
objectLiteralTypeAssertions?: 'allow' | 'allow-as-parameter' | 'never';
+ arrayLiteralTypeAssertions?: 'allow' | 'allow-as-parameter' | 'never';
}
| {
assertionStyle: 'never';
};
export type Options = readonly [OptUnion];
+type AsExpressionOrTypeAssertion =
+ | TSESTree.TSAsExpression
+ | TSESTree.TSTypeAssertion;
+
export default createRule({
name: 'consistent-type-assertions',
meta: {
@@ -45,10 +53,15 @@ export default createRule({
'angle-bracket': "Use '<{{cast}}>' instead of 'as {{cast}}'.",
as: "Use 'as {{cast}}' instead of '<{{cast}}>'.",
never: 'Do not use any type assertions.',
+ replaceArrayTypeAssertionWithAnnotation:
+ 'Use const x: {{cast}} = [ ... ] instead.',
+ replaceArrayTypeAssertionWithSatisfies:
+ 'Use const x = [ ... ] satisfies {{cast}} instead.',
replaceObjectTypeAssertionWithAnnotation:
'Use const x: {{cast}} = { ... } instead.',
replaceObjectTypeAssertionWithSatisfies:
'Use const x = { ... } satisfies {{cast}} instead.',
+ unexpectedArrayTypeAssertion: 'Always prefer const x: T[] = [ ... ].',
unexpectedObjectTypeAssertion: 'Always prefer const x: T = { ... }.',
},
schema: [
@@ -70,6 +83,12 @@ export default createRule({
type: 'object',
additionalProperties: false,
properties: {
+ arrayLiteralTypeAssertions: {
+ type: 'string',
+ description:
+ 'Whether to always prefer type declarations for array literals used as variable initializers, rather than type assertions.',
+ enum: ['allow', 'allow-as-parameter', 'never'],
+ },
assertionStyle: {
type: 'string',
description: 'The expected assertion style to enforce.',
@@ -89,6 +108,7 @@ export default createRule({
},
defaultOptions: [
{
+ arrayLiteralTypeAssertions: 'allow',
assertionStyle: 'as',
objectLiteralTypeAssertions: 'allow',
},
@@ -106,7 +126,7 @@ export default createRule({
}
function reportIncorrectAssertionType(
- node: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion,
+ node: AsExpressionOrTypeAssertion,
): void {
const messageId = options.assertionStyle;
@@ -192,8 +212,63 @@ export default createRule({
}
}
- function checkExpression(
- node: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion,
+ function getSuggestions(
+ node: AsExpressionOrTypeAssertion,
+ annotationMessageId: MessageIds,
+ satisfiesMessageId: MessageIds,
+ ): TSESLint.ReportSuggestionArray {
+ const suggestions: TSESLint.ReportSuggestionArray = [];
+ if (
+ node.parent.type === AST_NODE_TYPES.VariableDeclarator &&
+ !node.parent.id.typeAnnotation
+ ) {
+ const { parent } = node;
+ suggestions.push({
+ messageId: annotationMessageId,
+ data: { cast: context.sourceCode.getText(node.typeAnnotation) },
+ fix: fixer => [
+ fixer.insertTextAfter(
+ parent.id,
+ `: ${context.sourceCode.getText(node.typeAnnotation)}`,
+ ),
+ fixer.replaceText(
+ node,
+ getTextWithParentheses(context.sourceCode, node.expression),
+ ),
+ ],
+ });
+ }
+ suggestions.push({
+ messageId: satisfiesMessageId,
+ data: { cast: context.sourceCode.getText(node.typeAnnotation) },
+ fix: fixer => [
+ fixer.replaceText(
+ node,
+ getTextWithParentheses(context.sourceCode, node.expression),
+ ),
+ fixer.insertTextAfter(
+ node,
+ ` satisfies ${context.sourceCode.getText(node.typeAnnotation)}`,
+ ),
+ ],
+ });
+ return suggestions;
+ }
+
+ function isAsParameter(node: AsExpressionOrTypeAssertion): boolean {
+ return (
+ node.parent.type === AST_NODE_TYPES.NewExpression ||
+ node.parent.type === AST_NODE_TYPES.CallExpression ||
+ node.parent.type === AST_NODE_TYPES.ThrowStatement ||
+ node.parent.type === AST_NODE_TYPES.AssignmentPattern ||
+ node.parent.type === AST_NODE_TYPES.JSXExpressionContainer ||
+ (node.parent.type === AST_NODE_TYPES.TemplateLiteral &&
+ node.parent.parent.type === AST_NODE_TYPES.TaggedTemplateExpression)
+ );
+ }
+
+ function checkExpressionForObjectAssertion(
+ node: AsExpressionOrTypeAssertion,
): void {
if (
options.assertionStyle === 'never' ||
@@ -205,54 +280,17 @@ export default createRule({
if (
options.objectLiteralTypeAssertions === 'allow-as-parameter' &&
- (node.parent.type === AST_NODE_TYPES.NewExpression ||
- node.parent.type === AST_NODE_TYPES.CallExpression ||
- node.parent.type === AST_NODE_TYPES.ThrowStatement ||
- node.parent.type === AST_NODE_TYPES.AssignmentPattern ||
- node.parent.type === AST_NODE_TYPES.JSXExpressionContainer ||
- (node.parent.type === AST_NODE_TYPES.TemplateLiteral &&
- node.parent.parent.type ===
- AST_NODE_TYPES.TaggedTemplateExpression))
+ isAsParameter(node)
) {
return;
}
if (checkType(node.typeAnnotation)) {
- const suggest: TSESLint.ReportSuggestionArray = [];
- if (
- node.parent.type === AST_NODE_TYPES.VariableDeclarator &&
- !node.parent.id.typeAnnotation
- ) {
- const { parent } = node;
- suggest.push({
- messageId: 'replaceObjectTypeAssertionWithAnnotation',
- data: { cast: context.sourceCode.getText(node.typeAnnotation) },
- fix: fixer => [
- fixer.insertTextAfter(
- parent.id,
- `: ${context.sourceCode.getText(node.typeAnnotation)}`,
- ),
- fixer.replaceText(
- node,
- getTextWithParentheses(context.sourceCode, node.expression),
- ),
- ],
- });
- }
- suggest.push({
- messageId: 'replaceObjectTypeAssertionWithSatisfies',
- data: { cast: context.sourceCode.getText(node.typeAnnotation) },
- fix: fixer => [
- fixer.replaceText(
- node,
- getTextWithParentheses(context.sourceCode, node.expression),
- ),
- fixer.insertTextAfter(
- node,
- ` satisfies ${context.sourceCode.getText(node.typeAnnotation)}`,
- ),
- ],
- });
+ const suggest = getSuggestions(
+ node,
+ 'replaceObjectTypeAssertionWithAnnotation',
+ 'replaceObjectTypeAssertionWithSatisfies',
+ );
context.report({
node,
@@ -262,6 +300,39 @@ export default createRule({
}
}
+ function checkExpressionForArrayAssertion(
+ node: AsExpressionOrTypeAssertion,
+ ): void {
+ if (
+ options.assertionStyle === 'never' ||
+ options.arrayLiteralTypeAssertions === 'allow' ||
+ node.expression.type !== AST_NODE_TYPES.ArrayExpression
+ ) {
+ return;
+ }
+
+ if (
+ options.arrayLiteralTypeAssertions === 'allow-as-parameter' &&
+ isAsParameter(node)
+ ) {
+ return;
+ }
+
+ if (checkType(node.typeAnnotation)) {
+ const suggest = getSuggestions(
+ node,
+ 'replaceArrayTypeAssertionWithAnnotation',
+ 'replaceArrayTypeAssertionWithSatisfies',
+ );
+
+ context.report({
+ node,
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggest,
+ });
+ }
+ }
+
return {
TSAsExpression(node): void {
if (options.assertionStyle !== 'as') {
@@ -269,7 +340,8 @@ export default createRule({
return;
}
- checkExpression(node);
+ checkExpressionForObjectAssertion(node);
+ checkExpressionForArrayAssertion(node);
},
TSTypeAssertion(node): void {
if (options.assertionStyle !== 'angle-bracket') {
@@ -277,7 +349,8 @@ export default createRule({
return;
}
- checkExpression(node);
+ checkExpressionForObjectAssertion(node);
+ checkExpressionForArrayAssertion(node);
},
};
},
diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/consistent-type-assertions.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/consistent-type-assertions.shot
index 755dc6eb472d..7289fa881592 100644
--- a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/consistent-type-assertions.shot
+++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/consistent-type-assertions.shot
@@ -57,3 +57,61 @@ function bar() {
const foo = ;
"
`;
+
+exports[`Validating rule docs consistent-type-assertions.mdx code examples ESLint output 5`] = `
+"Incorrect
+Options: { "assertionStyle": "as", "arrayLiteralTypeAssertions": "never" }
+
+const x = ['foo'] as T;
+ ~~~~~~~~~~~~ Always prefer const x: T[] = [ ... ].
+
+function bar() {
+ return ['foo'] as T;
+ ~~~~~~~~~~~~ Always prefer const x: T[] = [ ... ].
+}
+"
+`;
+
+exports[`Validating rule docs consistent-type-assertions.mdx code examples ESLint output 6`] = `
+"Correct
+Options: { "assertionStyle": "as", "arrayLiteralTypeAssertions": "never" }
+
+const x: T = ['foo'];
+const y = ['foo'] as any;
+const z = ['foo'] as unknown;
+
+function bar(): T {
+ return ['foo'];
+}
+"
+`;
+
+exports[`Validating rule docs consistent-type-assertions.mdx code examples ESLint output 7`] = `
+"Incorrect
+Options: { "assertionStyle": "as", "arrayLiteralTypeAssertions": "allow-as-parameter" }
+
+const x = ['foo'] as T;
+ ~~~~~~~~~~~~ Always prefer const x: T[] = [ ... ].
+
+function bar() {
+ return ['foo'] as T;
+ ~~~~~~~~~~~~ Always prefer const x: T[] = [ ... ].
+}
+"
+`;
+
+exports[`Validating rule docs consistent-type-assertions.mdx code examples ESLint output 8`] = `
+"Correct
+Options: { "assertionStyle": "as", "arrayLiteralTypeAssertions": "allow-as-parameter" }
+
+const x: T = ['foo'];
+const y = ['foo'] as any;
+const z = ['foo'] as unknown;
+bar(['foo'] as T);
+new Clazz(['foo'] as T);
+function bar() {
+ throw ['foo'] as Foo;
+}
+const foo = ;
+"
+`;
diff --git a/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts b/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts
index efd24bd7c4ba..b2a1c47fff3f 100644
--- a/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts
+++ b/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts
@@ -136,6 +136,182 @@ ruleTester.run('consistent-type-assertions', rule, {
},
],
}),
+ {
+ code: 'const x = [] as string[];',
+ options: [
+ {
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: "const x = ['a'] as Array;",
+ options: [
+ {
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'const x = [];',
+ options: [
+ {
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: 'const x = >[];',
+ options: [
+ {
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: 'print([5] as Foo);',
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: `
+function foo() {
+ throw [5] as Foo;
+}
+ `,
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'function b(x = [5] as Foo.Bar) {}',
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'print?.([5] as Foo);',
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'print?.call([5] as Foo);',
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'print`${[5] as Foo}`;',
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'new Print([5] as Foo);',
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'const bar = ;',
+ languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } },
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'print([5]);',
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: `
+function foo() {
+ throw [5];
+}
+ `,
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: 'function b(x = [5]) {}',
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: 'print?.([5]);',
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: 'print?.call([5]);',
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: 'print`${[5]}`;',
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: 'new Print([5]);',
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
{ code: 'const x = [1];', options: [{ assertionStyle: 'never' }] },
{ code: 'const x = [1] as const;', options: [{ assertionStyle: 'never' }] },
{
@@ -671,5 +847,362 @@ const bs = (x <<= y) as any;
],
output: 'const ternary = (true ? x : y) as any;',
},
+ {
+ code: 'const x = [] as string[];',
+ errors: [
+ {
+ messageId: 'never',
+ },
+ ],
+ options: [
+ {
+ assertionStyle: 'never',
+ },
+ ],
+ },
+ {
+ code: 'const x = [];',
+ errors: [
+ {
+ messageId: 'never',
+ },
+ ],
+ options: [
+ {
+ assertionStyle: 'never',
+ },
+ ],
+ },
+ {
+ code: 'const x = [] as string[];',
+ errors: [
+ {
+ messageId: 'angle-bracket',
+ },
+ ],
+ options: [
+ {
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: 'const x = [];',
+ errors: [
+ {
+ messageId: 'as',
+ },
+ ],
+ options: [
+ {
+ assertionStyle: 'as',
+ },
+ ],
+ output: 'const x = [] as string[];',
+ },
+ {
+ code: 'const x = [] as string[];',
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'string[]' },
+ messageId: 'replaceArrayTypeAssertionWithAnnotation',
+ output: 'const x: string[] = [];',
+ },
+ {
+ data: { cast: 'string[]' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: 'const x = [] satisfies string[];',
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'never',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'const x = [];',
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'string[]' },
+ messageId: 'replaceArrayTypeAssertionWithAnnotation',
+ output: 'const x: string[] = [];',
+ },
+ {
+ data: { cast: 'string[]' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: 'const x = [] satisfies string[];',
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'never',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: 'print([5] as Foo);',
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'Foo' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: `print([5] satisfies Foo);`,
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'never',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'new print([5] as Foo);',
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'Foo' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: `new print([5] satisfies Foo);`,
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'never',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'function b(x = [5] as Foo.Bar) {}',
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'Foo.Bar' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: `function b(x = [5] satisfies Foo.Bar) {}`,
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'never',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: `
+function foo() {
+ throw [5] as Foo;
+}
+ `,
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'Foo' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: `
+function foo() {
+ throw [5] satisfies Foo;
+}
+ `,
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'never',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'print`${[5] as Foo}`;',
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'Foo' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: 'print`${[5] satisfies Foo}`;',
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'never',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'const foo = () => [5] as Foo;',
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'Foo' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: 'const foo = () => [5] satisfies Foo;',
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'as',
+ },
+ ],
+ },
+ {
+ code: 'new print([5]);',
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'Foo' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: `new print([5] satisfies Foo);`,
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'never',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: 'function b(x = [5]) {}',
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'Foo.Bar' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: `function b(x = [5] satisfies Foo.Bar) {}`,
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'never',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: `
+function foo() {
+ throw [5];
+}
+ `,
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'Foo' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: `
+function foo() {
+ throw [5] satisfies Foo;
+}
+ `,
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'never',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: 'print`${[5]}`;',
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'Foo' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: 'print`${[5] satisfies Foo}`;',
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'never',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
+ {
+ code: 'const foo = [5];',
+ errors: [
+ {
+ messageId: 'unexpectedArrayTypeAssertion',
+ suggestions: [
+ {
+ data: { cast: 'Foo' },
+ messageId: 'replaceArrayTypeAssertionWithAnnotation',
+ output: 'const foo: Foo = [5];',
+ },
+ {
+ data: { cast: 'Foo' },
+ messageId: 'replaceArrayTypeAssertionWithSatisfies',
+ output: 'const foo = [5] satisfies Foo;',
+ },
+ ],
+ },
+ ],
+ options: [
+ {
+ arrayLiteralTypeAssertions: 'allow-as-parameter',
+ assertionStyle: 'angle-bracket',
+ },
+ ],
+ },
],
});
diff --git a/packages/eslint-plugin/tests/schema-snapshots/consistent-type-assertions.shot b/packages/eslint-plugin/tests/schema-snapshots/consistent-type-assertions.shot
index 7845d5b791bb..a999506e695e 100644
--- a/packages/eslint-plugin/tests/schema-snapshots/consistent-type-assertions.shot
+++ b/packages/eslint-plugin/tests/schema-snapshots/consistent-type-assertions.shot
@@ -22,6 +22,11 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos
{
"additionalProperties": false,
"properties": {
+ "arrayLiteralTypeAssertions": {
+ "description": "Whether to always prefer type declarations for array literals used as variable initializers, rather than type assertions.",
+ "enum": ["allow", "allow-as-parameter", "never"],
+ "type": "string"
+ },
"assertionStyle": {
"description": "The expected assertion style to enforce.",
"enum": ["angle-bracket", "as"],
@@ -49,6 +54,12 @@ type Options = [
'never';
}
| {
+ /** Whether to always prefer type declarations for array literals used as variable initializers, rather than type assertions. */
+ arrayLiteralTypeAssertions?:
+ | 'allow-as-parameter'
+ | 'never'
+ /** Whether to always prefer type declarations for array literals used as variable initializers, rather than type assertions. */
+ | 'allow';
/** The expected assertion style to enforce. */
assertionStyle?:
| 'as'