diff --git a/packages/eslint-plugin/docs/rules/restrict-template-expressions.md b/packages/eslint-plugin/docs/rules/restrict-template-expressions.md index 549da98eebd..4c52e74445f 100644 --- a/packages/eslint-plugin/docs/rules/restrict-template-expressions.md +++ b/packages/eslint-plugin/docs/rules/restrict-template-expressions.md @@ -59,6 +59,16 @@ const msg1 = `arg = ${arg}`; const msg2 = `arg = ${arg || 'not truthy'}`; ``` +### `allowAny` + +Examples of additional **correct** code for this rule with `{ allowAny: true }`: + +```ts +const user = JSON.parse('{ "name": "foo" }'); +const msg1 = `arg = ${user.name}`; +const msg2 = `arg = ${user.name || 'the user with no name'}`; +``` + ### `allowNullable` Examples of additional **correct** code for this rule with `{ allowNullable: true }`: diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts index 6ff1627daf5..63b257ffe7f 100644 --- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts +++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts @@ -10,6 +10,7 @@ type Options = [ allowNullable?: boolean; allowNumber?: boolean; allowBoolean?: boolean; + allowAny?: boolean; }, ]; @@ -32,6 +33,7 @@ export default util.createRule({ { type: 'object', properties: { + allowAny: { type: 'boolean' }, allowBoolean: { type: 'boolean' }, allowNullable: { type: 'boolean' }, allowNumber: { type: 'boolean' }, @@ -51,6 +53,7 @@ export default util.createRule({ | 'boolean' | 'null' | 'undefined' + | 'any' | 'other'; const allowedTypes: BaseType[] = [ @@ -58,6 +61,7 @@ export default util.createRule({ ...(options.allowNumber ? (['number', 'bigint'] as const) : []), ...(options.allowBoolean ? (['boolean'] as const) : []), ...(options.allowNullable ? (['null', 'undefined'] as const) : []), + ...(options.allowAny ? (['any'] as const) : []), ]; function isAllowedType(types: BaseType[]): boolean { @@ -127,6 +131,9 @@ export default util.createRule({ if (type.flags & ts.TypeFlags.Undefined) { return ['undefined']; } + if (type.flags & ts.TypeFlags.Any) { + return ['any']; + } if (type.isUnion()) { return type.types @@ -139,7 +146,8 @@ export default util.createRule({ stringType === 'string' || stringType === 'number' || stringType === 'bigint' || - stringType === 'boolean' + stringType === 'boolean' || + stringType === 'any' ) { return [stringType]; } diff --git a/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts b/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts index 3e18e7ac1b1..6a2861efa32 100644 --- a/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts +++ b/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts @@ -115,6 +115,43 @@ ruleTester.run('restrict-template-expressions', rule, { } `, }, + // allowAny + { + options: [{ allowAny: true }], + code: ` + const arg: any = 123; + const msg = \`arg = \${arg}\`; + `, + }, + { + options: [{ allowAny: true }], + code: ` + const arg: any = undefined; + const msg = \`arg = \${arg || 'some-default'}\`; + `, + }, + { + options: [{ allowAny: true }], + code: ` + const user = JSON.parse('{ "name": "foo" }'); + const msg = \`arg = \${user.name}\`; + `, + }, + { + options: [{ allowAny: true }], + code: ` + const user = JSON.parse('{ "name": "foo" }'); + const msg = \`arg = \${user.name || 'the user with no name'}\`; + `, + }, + { + options: [{ allowAny: true }], + code: ` + function test(arg: T) { + return \`arg = \${arg}\`; + } + `, + }, // allowNullable { options: [{ allowNullable: true }], @@ -208,5 +245,14 @@ ruleTester.run('restrict-template-expressions', rule, { `, errors: [{ messageId: 'invalidType', line: 3, column: 27 }], }, + { + options: [{ allowNumber: true, allowBoolean: true, allowNullable: true }], + code: ` + function test(arg: any) { + return \`arg = \${arg}\`; + } + `, + errors: [{ messageId: 'invalidType', line: 3, column: 27 }], + }, ], });