diff --git a/packages/eslint-plugin/docs/rules/consistent-type-assertions.md b/packages/eslint-plugin/docs/rules/consistent-type-assertions.md index eb0fb521374..31fa341b97b 100644 --- a/packages/eslint-plugin/docs/rules/consistent-type-assertions.md +++ b/packages/eslint-plugin/docs/rules/consistent-type-assertions.md @@ -12,15 +12,18 @@ Type assertions are also commonly referred as "type casting" in TypeScript (even type Options = | { assertionStyle: 'as' | 'angle-bracket'; - objectLiteralTypeAssertions: 'allow' | 'allow-as-parameter' | 'never'; + objectLiteralTypeAssertions?: 'allow' | 'allow-as-parameter' | 'never'; + allowAsReturn?: boolean; } | { assertionStyle: 'never'; + allowAsReturn?: boolean; }; const defaultOptions: Options = { assertionStyle: 'as', objectLiteralTypeAssertions: 'allow', + allowAsReturn: false, }; ``` @@ -44,10 +47,15 @@ The compiler will warn for excess properties with this syntax, but not missing _ The const assertion `const x = { foo: 1 } as const`, introduced in TypeScript 3.4, is considered beneficial and is ignored by this option. +### `allowAsReturn` + +Allow type assertions on object literals if they are in a return statement. + Examples of **incorrect** code for `{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }` (and for `{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow-as-parameter' }`) ```ts const x = { ... } as T; +return {} as T; ``` Examples of **correct** code for `{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }`. @@ -69,6 +77,12 @@ new Clazz({ ... } as T); function foo() { throw { bar: 5 } as Foo } ``` +Examples of **correct** code for `{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow-as-parameter', allowAsReturn: true }`. + +```ts +return {} as T; +``` + ## 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 ae54149d0a7..082d02d1076 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts @@ -15,9 +15,11 @@ type OptUnion = | { assertionStyle: 'as' | 'angle-bracket'; objectLiteralTypeAssertions?: 'allow' | 'allow-as-parameter' | 'never'; + allowAsReturn?: boolean; } | { assertionStyle: 'never'; + allowAsReturn?: boolean; }; type Options = [OptUnion]; @@ -45,6 +47,7 @@ export default util.createRule({ assertionStyle: { enum: ['never'], }, + allowAsReturn: { type: 'boolean' }, }, additionalProperties: false, required: ['assertionStyle'], @@ -58,6 +61,7 @@ export default util.createRule({ objectLiteralTypeAssertions: { enum: ['allow', 'allow-as-parameter', 'never'], }, + allowAsReturn: { type: 'boolean' }, }, additionalProperties: false, required: ['assertionStyle'], @@ -70,6 +74,7 @@ export default util.createRule({ { assertionStyle: 'as', objectLiteralTypeAssertions: 'allow', + allowAsReturn: false, }, ], create(context, [options]) { @@ -131,6 +136,14 @@ export default util.createRule({ return; } + if ( + options.allowAsReturn && + node.parent && + node.parent.type === AST_NODE_TYPES.ReturnStatement + ) { + return; + } + if ( checkType(node.typeAnnotation) && node.expression.type === AST_NODE_TYPES.ObjectExpression 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 f885d503091..fd090342add 100644 --- a/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts +++ b/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts @@ -41,6 +41,9 @@ function foo() { throw { bar: 5 } } print?.({ bar: 5 }) print?.call({ bar: 5 }) `; +const OBJECT_LITERAL_RETURN = ` +return {} as Foo +`; ruleTester.run('consistent-type-assertions', rule, { valid: [ @@ -89,6 +92,16 @@ ruleTester.run('consistent-type-assertions', rule, { }, ], }), + ...batchedSingleLineTests({ + code: OBJECT_LITERAL_RETURN, + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'never', + allowAsReturn: true, + }, + ], + }), ...batchedSingleLineTests({ code: OBJECT_LITERAL_ARGUMENT_ANGLE_BRACKET_CASTS, options: [ @@ -328,5 +341,21 @@ ruleTester.run('consistent-type-assertions', rule, { }, ], }), + ...batchedSingleLineTests({ + code: OBJECT_LITERAL_RETURN, + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'never', + allowAsReturn: false, + }, + ], + errors: [ + { + messageId: 'unexpectedObjectTypeAssertion', + line: 2, + }, + ], + }), ], });