diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-type-parameters.ts b/packages/eslint-plugin/src/rules/no-unnecessary-type-parameters.ts index f66f75482289..3a486639dff7 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-parameters.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-parameters.ts @@ -10,6 +10,7 @@ import type { MakeRequired } from '../util'; import { createRule, getParserServices, + getWrappingFixer, nullThrows, NullThrowsReasons, } from '../util'; @@ -108,7 +109,28 @@ export default createRule({ for (const reference of smTypeParameterVariable.references) { if (reference.isTypeReference) { const referenceNode = reference.identifier; - yield fixer.replaceText(referenceNode, constraintText); + const isComplexType = + constraint?.type === AST_NODE_TYPES.TSUnionType || + constraint?.type === AST_NODE_TYPES.TSIntersectionType || + constraint?.type === AST_NODE_TYPES.TSConditionalType; + const hasMatchingAncestorType = [ + AST_NODE_TYPES.TSArrayType, + AST_NODE_TYPES.TSIndexedAccessType, + AST_NODE_TYPES.TSIntersectionType, + AST_NODE_TYPES.TSUnionType, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + ].some(type => referenceNode.parent.parent!.type === type); + if (isComplexType && hasMatchingAncestorType) { + const fixResult = getWrappingFixer({ + node: referenceNode, + innerNode: constraint, + sourceCode: context.sourceCode, + wrap: constraintNode => constraintNode, + })(fixer); + yield fixResult; + } else { + yield fixer.replaceText(referenceNode, constraintText); + } } } diff --git a/packages/eslint-plugin/src/util/getWrappingFixer.ts b/packages/eslint-plugin/src/util/getWrappingFixer.ts index 26afcaa6405b..2ad20e1d4893 100644 --- a/packages/eslint-plugin/src/util/getWrappingFixer.ts +++ b/packages/eslint-plugin/src/util/getWrappingFixer.ts @@ -32,7 +32,7 @@ interface WrappingFixerParams { */ export function getWrappingFixer( params: WrappingFixerParams, -): TSESLint.ReportFixFunction { +): (fixer: TSESLint.RuleFixer) => TSESLint.RuleFix { const { node, innerNode = node, sourceCode, wrap } = params; const innerNodes = Array.isArray(innerNode) ? innerNode : [innerNode]; diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-type-parameters.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-type-parameters.test.ts index cba7279691f3..9f8f05479c9c 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-type-parameters.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-type-parameters.test.ts @@ -1744,5 +1744,172 @@ class Joiner { }, ], }, + { + code: ` +function join(els: T[]) { + return els.map(el => '' + el).join(','); +} + `, + errors: [ + { + data: { descriptor: 'function', name: 'T', uses: 'used only once' }, + messageId: 'sole', + suggestions: [ + { + messageId: 'replaceUsagesWithConstraint', + output: ` +function join(els: (string | number)[]) { + return els.map(el => '' + el).join(','); +} + `, + }, + ], + }, + ], + }, + { + code: ` +function join(els: T[]) { + return els.map(el => '' + el).join(','); +} + `, + errors: [ + { + data: { descriptor: 'function', name: 'T', uses: 'used only once' }, + messageId: 'sole', + suggestions: [ + { + messageId: 'replaceUsagesWithConstraint', + output: ` +function join(els: (string & number)[]) { + return els.map(el => '' + el).join(','); +} + `, + }, + ], + }, + ], + }, + { + code: ` +function join(els: T[]) { + return els.map(el => '' + el).join(','); +} + `, + errors: [ + { + data: { descriptor: 'function', name: 'T', uses: 'used only once' }, + messageId: 'sole', + suggestions: [ + { + messageId: 'replaceUsagesWithConstraint', + output: ` +function join(els: ((string & number) | boolean)[]) { + return els.map(el => '' + el).join(','); +} + `, + }, + ], + }, + ], + }, + { + code: noFormat` +function join(els: T[]) { + return els.map(el => '' + el).join(','); +} + `, + errors: [ + { + data: { descriptor: 'function', name: 'T', uses: 'used only once' }, + messageId: 'sole', + suggestions: [ + { + messageId: 'replaceUsagesWithConstraint', + output: ` +function join(els: (string | number)[]) { + return els.map(el => '' + el).join(','); +} + `, + }, + ], + }, + ], + }, + { + code: ` +function join(els: T['hoge'][]) { + return els.map(el => '' + el).join(','); +} + `, + errors: [ + { + data: { descriptor: 'function', name: 'T', uses: 'used only once' }, + messageId: 'sole', + suggestions: [ + { + messageId: 'replaceUsagesWithConstraint', + output: ` +function join(els: ({ hoge: string } | { hoge: number })['hoge'][]) { + return els.map(el => '' + el).join(','); +} + `, + }, + ], + }, + ], + }, + { + code: ` +type A = string; +type B = string; +type C = string; +declare function f(): T & C; + `, + errors: [ + { + data: { descriptor: 'function', name: 'T', uses: 'used only once' }, + messageId: 'sole', + suggestions: [ + { + messageId: 'replaceUsagesWithConstraint', + output: ` +type A = string; +type B = string; +type C = string; +declare function f(): (A | B) & C; + `, + }, + ], + }, + ], + }, + { + code: ` +type A = string; +type B = string; +type C = string; +type D = string; +declare function f(): T | null; + `, + errors: [ + { + data: { descriptor: 'function', name: 'T', uses: 'used only once' }, + messageId: 'sole', + suggestions: [ + { + messageId: 'replaceUsagesWithConstraint', + output: ` +type A = string; +type B = string; +type C = string; +type D = string; +declare function f(): (A extends B ? C : D) | null; + `, + }, + ], + }, + ], + }, ], }); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy