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 bbefaa06f4c..c11949c1e39 100644 --- a/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts +++ b/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts @@ -1,322 +1,405 @@ -/* eslint-disable @typescript-eslint/no-deprecated -- TODO - migrate this test away from `batchedSingleLineTests` */ - import type { TSESTree } from '@typescript-eslint/utils'; import * as parser from '@typescript-eslint/parser'; import { RuleTester } from '@typescript-eslint/rule-tester'; -import type { - MessageIds, - Options, -} from '../../src/rules/consistent-type-assertions'; - import rule from '../../src/rules/consistent-type-assertions'; -import { dedupeTestCases } from '../dedupeTestCases'; -import { batchedSingleLineTests } from '../RuleTester'; const ruleTester = new RuleTester(); -const ANGLE_BRACKET_TESTS_EXCEPT_CONST_CASE = ` -const x = new Generic(); -const x = b; -const x = [1]; -const x = ('string'); -const x = !'string'; -const x = a + b; -const x = <(A)>a + (b); -const x = (new Generic()); -const x = new (Generic)(); -const x = new (Generic)('string'); -const x = () => { bar: 5 }; -const x = () => ({ bar: 5 }); -const x = () => bar; -const x = bar\`\${"baz"}\`;`; - -const ANGLE_BRACKET_TESTS = `${ANGLE_BRACKET_TESTS_EXCEPT_CONST_CASE} -const x = { key: 'value' }; -`; - -// Intentionally contains a duplicate in order to mirror ANGLE_BRACKET_TESTS_EXCEPT_CONST_CASE -const AS_TESTS_EXCEPT_CONST_CASE = ` -const x = new Generic() as Foo; -const x = b as A; -const x = [1] as readonly number[]; -const x = 'string' as a | b; -const x = !'string' as A; -const x = (a as A) + b; -const x = (a as A) + (b); -const x = new Generic() as Foo; -const x = new ((Generic) as Foo)(); -const x = new ((Generic) as Foo)('string'); -const x = () => ({ bar: 5 } as Foo); -const x = () => ({ bar: 5 } as Foo); -const x = () => (bar as Foo); -const x = bar\`\${"baz"}\` as Foo;`; - -const AS_TESTS = `${AS_TESTS_EXCEPT_CONST_CASE} -const x = { key: 'value' } as const; -`; - -const OBJECT_LITERAL_AS_CASTS = ` -const x = {} as Foo; -const x = ({}) as a | b; -const x = {} as A + b; -`; -const OBJECT_LITERAL_ANGLE_BRACKET_CASTS = ` -const x = >{}; -const x = ({}); -const x = {} + b; -`; -const OBJECT_LITERAL_ARGUMENT_AS_CASTS = ` -print({ bar: 5 } as Foo) -new print({ bar: 5 } as Foo) -function foo() { throw { bar: 5 } as Foo } -function b(x = {} as Foo.Bar) {} -function c(x = {} as Foo) {} -print?.({ bar: 5 } as Foo) -print?.call({ bar: 5 } as Foo) -print\`\${{ bar: 5 } as Foo}\` -`; -const OBJECT_LITERAL_ARGUMENT_ANGLE_BRACKET_CASTS = ` -print({ bar: 5 }) -new print({ bar: 5 }) -function foo() { throw { bar: 5 } } -print?.({ bar: 5 }) -print?.call({ bar: 5 }) -print\`\${{ bar: 5 }}\` -`; - ruleTester.run('consistent-type-assertions', rule, { valid: [ - ...dedupeTestCases( - batchedSingleLineTests({ - code: AS_TESTS, - options: [ - { assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }, - ], - }), - ), - ...batchedSingleLineTests({ - code: ANGLE_BRACKET_TESTS, + { + code: 'const x = new Generic() as Foo;', options: [ { - assertionStyle: 'angle-bracket', + assertionStyle: 'as', objectLiteralTypeAssertions: 'allow', }, ], - }), - ...batchedSingleLineTests({ - code: `${OBJECT_LITERAL_AS_CASTS.trimEnd()}${OBJECT_LITERAL_ARGUMENT_AS_CASTS}`, - options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }], - }), - ...batchedSingleLineTests({ - code: `${OBJECT_LITERAL_ANGLE_BRACKET_CASTS.trimEnd()}${OBJECT_LITERAL_ARGUMENT_ANGLE_BRACKET_CASTS}`, + }, + { + code: 'const x = b as A;', options: [ { - assertionStyle: 'angle-bracket', + assertionStyle: 'as', objectLiteralTypeAssertions: 'allow', }, ], - }), - ...batchedSingleLineTests({ - code: OBJECT_LITERAL_ARGUMENT_AS_CASTS, + }, + { + code: 'const x = [1] as readonly number[];', options: [ { assertionStyle: 'as', - objectLiteralTypeAssertions: 'allow-as-parameter', + objectLiteralTypeAssertions: 'allow', }, ], - }), - ...batchedSingleLineTests({ - code: OBJECT_LITERAL_ARGUMENT_ANGLE_BRACKET_CASTS, + }, + { + code: "const x = 'string' as a | b;", options: [ { - assertionStyle: 'angle-bracket', - objectLiteralTypeAssertions: 'allow-as-parameter', + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', }, ], - }), + }, { - code: 'const x = [] as string[];', + code: "const x = !'string' as A;", options: [ { assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: "const x = ['a'] as Array;", + code: 'const x = (a as A) + b;', options: [ { assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'const x = [];', + code: 'const x = new Generic() as Foo;', options: [ { - assertionStyle: 'angle-bracket', + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'const x = >[];', + code: 'const x = new (Generic as Foo)();', options: [ { - assertionStyle: 'angle-bracket', + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'print([5] as Foo);', + code: "const x = new (Generic as Foo)('string');", options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: ` -function foo() { - throw [5] as Foo; -} - `, + code: 'const x = () => ({ bar: 5 }) as Foo;', options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'function b(x = [5] as Foo.Bar) {}', + code: 'const x = () => bar as Foo;', options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'print?.([5] as Foo);', + code: "const x = bar`${'baz'}` as Foo;", options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'print?.call([5] as Foo);', + code: "const x = { key: 'value' } as const;", options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'print`${[5] as Foo}`;', + code: 'const x = new Generic();', options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', - assertionStyle: 'as', + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'new Print([5] as Foo);', + code: 'const x = b;', options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', - assertionStyle: 'as', + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'const bar = ;', - languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } }, + code: 'const x = [1];', options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', - assertionStyle: 'as', + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'print([5]);', + code: "const x = 'string';", + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }, + { + code: "const x = !'string';", + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }, + { + code: 'const x = a + b;', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }, + { + code: 'const x = new Generic();', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }, + { + code: 'const x = new (Generic)();', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }, + { + code: "const x = new (Generic)('string');", + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }, + { + code: 'const x = () => { bar: 5 };', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }, + { + code: 'const x = () => bar;', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }, + { + code: "const x = bar`${'baz'}`;", + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }, + { + code: "const x = { key: 'value' };", options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', }, ], }, + { + code: 'const x = {} as Foo;', + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }], + }, + { + code: 'const x = {} as a | b;', + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }], + }, + { + code: 'const x = ({} as A) + b;', + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }], + }, + { + code: 'print({ bar: 5 } as Foo);', + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }], + }, + { + code: 'new print({ bar: 5 } as Foo);', + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }], + }, { code: ` function foo() { - throw [5]; + throw { bar: 5 } as Foo; } `, + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }], + }, + { + code: 'function b(x = {} as Foo.Bar) {}', + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }], + }, + { + code: 'function c(x = {} as Foo) {}', + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }], + }, + { + code: 'print?.({ bar: 5 } as Foo);', + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }], + }, + { + code: 'print?.call({ bar: 5 } as Foo);', + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }], + }, + { + code: 'print`${{ bar: 5 } as Foo}`;', + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow' }], + }, + { + code: 'const x = >{};', options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'function b(x = [5]) {}', + code: 'const x = {};', options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'print?.([5]);', + code: 'const x = {} + b;', options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'print?.call([5]);', + code: 'print({ bar: 5 });', options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'print`${[5]}`;', + code: 'new print({ bar: 5 });', options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', }, ], }, { - code: 'new Print([5]);', + code: ` +function foo() { + throw { bar: 5 }; +} + `, options: [ { - arrayLiteralTypeAssertions: 'allow-as-parameter', assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', }, ], }, - { code: 'const x = [1];', options: [{ assertionStyle: 'never' }] }, - { code: 'const x = [1] as const;', options: [{ assertionStyle: 'never' }] }, { - code: 'const bar = ;', - languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } }, + code: 'print?.({ bar: 5 });', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }, + { + code: 'print?.call({ bar: 5 });', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }, + { + code: 'print`${{ bar: 5 }}`;', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }, + { + code: 'print({ bar: 5 } as Foo);', + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'new print({ bar: 5 } as Foo);', + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: ` +function foo() { + throw { bar: 5 } as Foo; +} + `, options: [ { assertionStyle: 'as', @@ -325,52 +408,838 @@ function foo() { ], }, { - code: '123;', - languageOptions: { - // simulate a 3rd party parser that doesn't provide parser services - parser: { - parse: (): TSESTree.Program => parser.parse('123;'), + code: 'function b(x = {} as Foo.Bar) {}', + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'function c(x = {} as Foo) {}', + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'print?.({ bar: 5 } as Foo);', + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'print?.call({ bar: 5 } as Foo);', + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'print`${{ bar: 5 } as Foo}`;', + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'print({ bar: 5 });', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'new print({ bar: 5 });', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: ` +function foo() { + throw { bar: 5 }; +} + `, + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'print?.({ bar: 5 });', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'print?.call({ bar: 5 });', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'print`${{ bar: 5 }}`;', + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + + { + 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' }] }, + { + code: 'const bar = ;', + languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } }, + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: '123;', + languageOptions: { + // simulate a 3rd party parser that doesn't provide parser services + parser: { + parse: (): TSESTree.Program => parser.parse('123;'), + }, + }, + }, + { + code: ` +const x = { key: 'value' } as any; + `, + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + }, + { + code: ` +const x = { key: 'value' } as unknown; + `, + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + }, + ], + invalid: [ + { + code: 'const x = new Generic() as Foo;', + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: 'const x = b as A;', + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: 'const x = [1] as readonly number[];', + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: "const x = 'string' as a | b;", + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: "const x = !'string' as A;", + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: 'const x = (a as A) + b;', + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: 'const x = new Generic() as Foo;', + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: 'const x = new (Generic as Foo)();', + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: "const x = new (Generic as Foo)('string');", + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: 'const x = () => ({ bar: 5 }) as Foo;', + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: 'const x = () => bar as Foo;', + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: "const x = bar`${'baz'}` as Foo;", + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: "const x = { key: 'value' } as const;", + errors: [ + { + line: 1, + messageId: 'angle-bracket', + }, + ], + options: [{ assertionStyle: 'angle-bracket' }], + }, + { + code: 'const x = new Generic();', + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: 'const x = new Generic() as Foo;', + }, + { + code: 'const x = b;', + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: 'const x = b as A;', + }, + { + code: 'const x = [1];', + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: 'const x = [1] as readonly number[];', + }, + { + code: "const x = 'string';", + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: "const x = 'string' as a | b;", + }, + { + code: "const x = !'string';", + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: "const x = !'string' as A;", + }, + { + code: 'const x = a + b;', + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: 'const x = (a as A) + b;', + }, + { + code: 'const x = new Generic();', + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: 'const x = new Generic() as Foo;', + }, + { + code: 'const x = new (Generic)();', + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: 'const x = new ((Generic) as Foo)();', + }, + { + code: "const x = new (Generic)('string');", + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: "const x = new ((Generic) as Foo)('string');", + }, + { + code: 'const x = () => { bar: 5 };', + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: 'const x = () => ({ bar: 5 } as Foo);', + }, + { + code: 'const x = () => bar;', + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: 'const x = () => (bar as Foo);', + }, + { + code: "const x = bar`${'baz'}`;", + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: "const x = bar`${'baz'}` as Foo;", + }, + { + code: "const x = { key: 'value' };", + errors: [ + { + line: 1, + messageId: 'as', + }, + ], + options: [{ assertionStyle: 'as' }], + output: "const x = { key: 'value' } as const;", + }, + { + code: 'const x = new Generic() as Foo;', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = b as A;', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = [1] as readonly number[];', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: "const x = 'string' as a | b;", + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: "const x = !'string' as A;", + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = (a as A) + b;', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = new Generic() as Foo;', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = new (Generic as Foo)();', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: "const x = new (Generic as Foo)('string');", + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = () => ({ bar: 5 }) as Foo;', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = () => bar as Foo;', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: "const x = bar`${'baz'}` as Foo;", + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = new Generic();', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = b;', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = [1];', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: "const x = 'string';", + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: "const x = !'string';", + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = a + b;', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = new Generic();', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = new (Generic)();', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: "const x = new (Generic)('string');", + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = () => { bar: 5 };', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: 'const x = () => bar;', + errors: [ + { + line: 1, + messageId: 'never', + }, + ], + options: [{ assertionStyle: 'never' }], + }, + { + code: "const x = bar`${'baz'}`;", + errors: [ + { + line: 1, + messageId: 'never', }, - }, - }, - { - code: ` -const x = { key: 'value' } as any; - `, - options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + ], + options: [{ assertionStyle: 'never' }], }, { - code: ` -const x = { key: 'value' } as unknown; - `, - options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], - }, - ], - invalid: [ - ...dedupeTestCases( - ( - [ - ['angle-bracket', AS_TESTS], - ['as', ANGLE_BRACKET_TESTS, AS_TESTS], - ['never', AS_TESTS_EXCEPT_CONST_CASE], - ['never', ANGLE_BRACKET_TESTS_EXCEPT_CONST_CASE], - ] as const - ).flatMap(([assertionStyle, code, output]) => - batchedSingleLineTests({ - code, - errors: code - .split(`\n`) - .map((_, i) => ({ line: i + 1, messageId: assertionStyle })), - options: [{ assertionStyle }], - output, - }), - ), - ), - ...batchedSingleLineTests({ - code: OBJECT_LITERAL_AS_CASTS, - errors: [ - { - line: 2, + code: 'const x = {} as Foo;', + errors: [ + { + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { @@ -385,30 +1254,52 @@ const x = { key: 'value' } as unknown; }, ], }, + ], + options: [ { - line: 3, + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'const x = {} as a | b;', + errors: [ + { + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'a | b' }, messageId: 'replaceObjectTypeAssertionWithAnnotation', - output: 'const x: a | b = ({});', + output: 'const x: a | b = {};', }, { data: { cast: 'a | b' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'const x = ({}) satisfies a | b;', + output: 'const x = {} satisfies a | b;', }, ], }, + ], + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'const x = ({} as A) + b;', + errors: [ { - line: 4, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'A' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'const x = {} satisfies A + b;', + output: 'const x = ({} satisfies A) + b;', }, ], }, @@ -419,12 +1310,12 @@ const x = { key: 'value' } as unknown; objectLiteralTypeAssertions: 'allow-as-parameter', }, ], - }), - ...batchedSingleLineTests({ - code: OBJECT_LITERAL_ANGLE_BRACKET_CASTS, + }, + { + code: 'const x = >{};', errors: [ { - line: 2, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { @@ -439,24 +1330,46 @@ const x = { key: 'value' } as unknown; }, ], }, + ], + options: [ { - line: 3, + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'const x = {};', + errors: [ + { + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'a | b' }, messageId: 'replaceObjectTypeAssertionWithAnnotation', - output: 'const x: a | b = ({});', + output: 'const x: a | b = {};', }, { data: { cast: 'a | b' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'const x = ({}) satisfies a | b;', + output: 'const x = {} satisfies a | b;', }, ], }, + ], + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }, + { + code: 'const x = {} + b;', + errors: [ { - line: 4, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { @@ -473,12 +1386,12 @@ const x = { key: 'value' } as unknown; objectLiteralTypeAssertions: 'allow-as-parameter', }, ], - }), - ...batchedSingleLineTests({ - code: `${OBJECT_LITERAL_AS_CASTS.trimEnd()}${OBJECT_LITERAL_ARGUMENT_AS_CASTS}`, + }, + { + code: 'const x = {} as Foo;', errors: [ { - line: 2, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { @@ -493,68 +1406,112 @@ const x = { key: 'value' } as unknown; }, ], }, + ], + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + }, + { + code: 'const x = {} as a | b;', + errors: [ { - line: 3, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'a | b' }, messageId: 'replaceObjectTypeAssertionWithAnnotation', - output: 'const x: a | b = ({});', + output: 'const x: a | b = {};', }, { data: { cast: 'a | b' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'const x = ({}) satisfies a | b;', + output: 'const x = {} satisfies a | b;', }, ], }, + ], + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + }, + { + code: 'const x = ({} as A) + b;', + errors: [ { - line: 4, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'A' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'const x = {} satisfies A + b;', + output: 'const x = ({} satisfies A) + b;', }, ], }, + ], + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + }, + { + code: 'print({ bar: 5 } as Foo);', + errors: [ { - line: 5, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'Foo' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'print({ bar: 5 } satisfies Foo)', + output: 'print({ bar: 5 } satisfies Foo);', }, ], }, + ], + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + }, + { + code: 'new print({ bar: 5 } as Foo);', + errors: [ { - line: 6, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'Foo' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'new print({ bar: 5 } satisfies Foo)', + output: 'new print({ bar: 5 } satisfies Foo);', }, ], }, + ], + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + }, + { + code: ` +function foo() { + throw { bar: 5 } as Foo; +} + `, + errors: [ { - line: 7, + line: 3, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'Foo' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'function foo() { throw { bar: 5 } satisfies Foo }', + output: ` +function foo() { + throw { bar: 5 } satisfies Foo; +} + `, }, ], }, + ], + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + }, + { + code: 'function b(x = {} as Foo.Bar) {}', + errors: [ { - line: 8, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { @@ -564,8 +1521,14 @@ const x = { key: 'value' } as unknown; }, ], }, + ], + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + }, + { + code: 'function c(x = {} as Foo) {}', + errors: [ { - line: 9, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { @@ -575,47 +1538,65 @@ const x = { key: 'value' } as unknown; }, ], }, + ], + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + }, + { + code: 'print?.({ bar: 5 } as Foo);', + errors: [ { - line: 10, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'Foo' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'print?.({ bar: 5 } satisfies Foo)', + output: 'print?.({ bar: 5 } satisfies Foo);', }, ], }, + ], + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + }, + { + code: 'print?.call({ bar: 5 } as Foo);', + errors: [ { - line: 11, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'Foo' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'print?.call({ bar: 5 } satisfies Foo)', + output: 'print?.call({ bar: 5 } satisfies Foo);', }, ], }, + ], + options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], + }, + { + code: 'print`${{ bar: 5 } as Foo}`;', + errors: [ { - line: 12, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'Foo' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: `print\`\${{ bar: 5 } satisfies Foo}\``, + output: 'print`${{ bar: 5 } satisfies Foo}`;', }, ], }, ], options: [{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }], - }), - ...batchedSingleLineTests({ - code: `${OBJECT_LITERAL_ANGLE_BRACKET_CASTS.trimEnd()}${OBJECT_LITERAL_ARGUMENT_ANGLE_BRACKET_CASTS}`, + }, + { + code: 'const x = >{};', errors: [ { - line: 2, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { @@ -630,24 +1611,46 @@ const x = { key: 'value' } as unknown; }, ], }, + ], + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'never', + }, + ], + }, + { + code: 'const x = {};', + errors: [ { - line: 3, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'a | b' }, messageId: 'replaceObjectTypeAssertionWithAnnotation', - output: 'const x: a | b = ({});', + output: 'const x: a | b = {};', }, { data: { cast: 'a | b' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'const x = ({}) satisfies a | b;', + output: 'const x = {} satisfies a | b;', }, ], }, + ], + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'never', + }, + ], + }, + { + code: 'const x = {} + b;', + errors: [ { - line: 4, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { @@ -657,69 +1660,143 @@ const x = { key: 'value' } as unknown; }, ], }, + ], + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'never', + }, + ], + }, + { + code: 'print({ bar: 5 });', + errors: [ { - line: 5, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'Foo' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'print({ bar: 5 } satisfies Foo)', + output: 'print({ bar: 5 } satisfies Foo);', }, ], }, + ], + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'never', + }, + ], + }, + { + code: 'new print({ bar: 5 });', + errors: [ { - line: 6, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'Foo' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'new print({ bar: 5 } satisfies Foo)', + output: 'new print({ bar: 5 } satisfies Foo);', }, ], }, + ], + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'never', + }, + ], + }, + { + code: ` +function foo() { + throw { bar: 5 }; +} + `, + errors: [ { - line: 7, + line: 3, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'Foo' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'function foo() { throw { bar: 5 } satisfies Foo }', + output: ` +function foo() { + throw { bar: 5 } satisfies Foo; +} + `, }, ], }, + ], + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'never', + }, + ], + }, + { + code: 'print?.({ bar: 5 });', + errors: [ { - line: 8, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'Foo' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'print?.({ bar: 5 } satisfies Foo)', + output: 'print?.({ bar: 5 } satisfies Foo);', }, ], }, + ], + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'never', + }, + ], + }, + { + code: 'print?.call({ bar: 5 });', + errors: [ { - line: 9, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'Foo' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: 'print?.call({ bar: 5 } satisfies Foo)', + output: 'print?.call({ bar: 5 } satisfies Foo);', }, ], }, + ], + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'never', + }, + ], + }, + { + code: 'print`${{ bar: 5 }}`;', + errors: [ { - line: 10, + line: 1, messageId: 'unexpectedObjectTypeAssertion', suggestions: [ { data: { cast: 'Foo' }, messageId: 'replaceObjectTypeAssertionWithSatisfies', - output: `print\`\${{ bar: 5 } satisfies Foo}\``, + output: 'print`${{ bar: 5 } satisfies Foo}`;', }, ], }, @@ -730,7 +1807,7 @@ const x = { key: 'value' } as unknown; objectLiteralTypeAssertions: 'never', }, ], - }), + }, { code: 'const foo = ;', errors: [{ line: 1, messageId: 'never' }],