diff --git a/packages/eslint-plugin/docs/rules/consistent-generic-constructors.mdx b/packages/eslint-plugin/docs/rules/consistent-generic-constructors.mdx index e4c5e0708398..0426691ef469 100644 --- a/packages/eslint-plugin/docs/rules/consistent-generic-constructors.mdx +++ b/packages/eslint-plugin/docs/rules/consistent-generic-constructors.mdx @@ -79,6 +79,37 @@ const set: Set = new Set(); +### `ignore` + +{/* insert option description */} + +Some constructors have different type signatures between their type and value, for example like Uint8Array. + + + + +```ts option='"constructor"' +// Incorrect because Uint8Array has deffenrent type signature and not in ignorelist +let a: Uint8Array = new Uint8Array(); + +// Incorrect because type arguments appear in type-annotation and not in ignorelist +let a: UserConstructor = new UserConstructor(); +``` + + + + +```ts option='"constructor", { "ignore": ["Uint8Array", "UserConstructor"] }' showPlaygroundButton +// Correct because Uint8Array has deffenrent type signature but are included in the ignorelist. +let a: Uint8Array = new Uint8Array(); + +// Correct because type arguments appear in type-annotations but are included in the ignorelist. +let a: UserConstructor = new UserConstructor(); +``` + + + + ## When Not To Use It You can turn this rule off if you don't want to enforce one kind of generic constructor style over the other. diff --git a/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts b/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts index f2a4808d25dd..c6403b9ca9a6 100644 --- a/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts +++ b/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts @@ -4,8 +4,13 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import { createRule, nullThrows, NullThrowsReasons } from '../util'; -export type MessageIds = 'preferConstructor' | 'preferTypeAnnotation'; -export type Options = ['constructor' | 'type-annotation']; +type MessageIds = 'preferConstructor' | 'preferTypeAnnotation'; +type Options = [ + 'constructor' | 'type-annotation', + { + ignore?: string[]; + }?, +]; export default createRule({ name: 'consistent-generic-constructors', @@ -29,10 +34,24 @@ export default createRule({ description: 'Which constructor call syntax to prefer.', enum: ['type-annotation', 'constructor'], }, + { + type: 'object', + additionalProperties: false, + properties: { + ignore: { + type: 'array', + description: + 'A list of constructor names to ignore when enforcing the rule.', + items: { + type: 'string', + }, + }, + }, + }, ], }, - defaultOptions: ['constructor'], - create(context, [mode]) { + defaultOptions: ['constructor', {}], + create(context, [mode, options]) { return { 'VariableDeclarator,PropertyDefinition,AccessorProperty,:matches(FunctionDeclaration,FunctionExpression) > AssignmentPattern'( node: @@ -77,7 +96,8 @@ export default createRule({ lhs && (lhs.type !== AST_NODE_TYPES.TSTypeReference || lhs.typeName.type !== AST_NODE_TYPES.Identifier || - lhs.typeName.name !== rhs.callee.name) + lhs.typeName.name !== rhs.callee.name || + options?.ignore?.includes(lhs.typeName.name)) ) { return; } diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/consistent-generic-constructors.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/consistent-generic-constructors.shot index 1e63291e5fae..0ba060331449 100644 --- a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/consistent-generic-constructors.shot +++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/consistent-generic-constructors.shot @@ -44,3 +44,29 @@ const set = new Set(); const set: Set = new Set(); " `; + +exports[`Validating rule docs consistent-generic-constructors.mdx code examples ESLint output 5`] = ` +"Incorrect +Options: "constructor" + +// Incorrect because Uint8Array has deffenrent type signature and not in ignorelist +let a: Uint8Array = new Uint8Array(); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The generic type arguments should be specified as part of the constructor type arguments. + +// Incorrect because type arguments appear in type-annotation and not in ignorelist +let a: UserConstructor = new UserConstructor(); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The generic type arguments should be specified as part of the constructor type arguments. +" +`; + +exports[`Validating rule docs consistent-generic-constructors.mdx code examples ESLint output 6`] = ` +"Correct +Options: "constructor", { "ignore": ["Uint8Array", "UserConstructor"] } + +// Correct because Uint8Array has deffenrent type signature but are included in the ignorelist. +let a: Uint8Array = new Uint8Array(); + +// Correct because type arguments appear in type-annotations but are included in the ignorelist. +let a: UserConstructor = new UserConstructor(); +" +`; diff --git a/packages/eslint-plugin/tests/rules/consistent-generic-constructors.test.ts b/packages/eslint-plugin/tests/rules/consistent-generic-constructors.test.ts index 4d0403a85a87..475aa044939b 100644 --- a/packages/eslint-plugin/tests/rules/consistent-generic-constructors.test.ts +++ b/packages/eslint-plugin/tests/rules/consistent-generic-constructors.test.ts @@ -45,6 +45,10 @@ class A { ` const a = function (a: Foo = new Foo()) {}; `, + { + code: 'let a: Uint8Array = new Uint8Array();', + options: ['constructor', { ignore: ['Uint8Array'] }], + }, // type-annotation { code: 'const a = new Foo();', diff --git a/packages/eslint-plugin/tests/schema-snapshots/consistent-generic-constructors.shot b/packages/eslint-plugin/tests/schema-snapshots/consistent-generic-constructors.shot index 7f40a340e498..525a9b6d2215 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/consistent-generic-constructors.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/consistent-generic-constructors.shot @@ -9,6 +9,19 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "description": "Which constructor call syntax to prefer.", "enum": ["constructor", "type-annotation"], "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "ignore": { + "description": "A list of constructor names to ignore when enforcing the rule.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" } ] @@ -17,9 +30,15 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos type Options = [ /** Which constructor call syntax to prefer. */ - | 'type-annotation' - /** Which constructor call syntax to prefer. */ - | 'constructor', + ( + | 'type-annotation' + /** Which constructor call syntax to prefer. */ + | 'constructor' + ), + { + /** A list of constructor names to ignore when enforcing the rule. */ + ignore?: string[]; + }, ]; " `;