From ab2258a41880c9e9341a10973180d3a234379192 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Tue, 6 Aug 2024 13:01:30 -0400 Subject: [PATCH 1/3] fix(eslint-plugin): [no-unnecessary-type-parameters] clarify message --- .../src/rules/no-unnecessary-type-parameters.ts | 2 +- .../no-unnecessary-type-parameters.shot | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) 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 f191efa2f4e7..aa979d479dd6 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-parameters.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-parameters.ts @@ -21,7 +21,7 @@ export default createRule({ recommended: 'strict', }, messages: { - sole: 'Type parameter {{name}} is used only once.', + sole: 'Type parameter {{name}} is used only once in the function signature.', }, schema: [], type: 'problem', diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unnecessary-type-parameters.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unnecessary-type-parameters.shot index ff3a00a42b6e..7e52aaf3324d 100644 --- a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unnecessary-type-parameters.shot +++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unnecessary-type-parameters.shot @@ -4,17 +4,17 @@ exports[`Validating rule docs no-unnecessary-type-parameters.mdx code examples E "Incorrect function second(a: A, b: B): B { - ~ Type parameter A is used only once. + ~ Type parameter A is used only once in the function signature. return b; } function parseJSON(input: string): T { - ~ Type parameter T is used only once. + ~ Type parameter T is used only once in the function signature. return JSON.parse(input); } function printProperty(obj: T, key: K) { - ~~~~~~~~~~~~~~~~~ Type parameter K is used only once. + ~~~~~~~~~~~~~~~~~ Type parameter K is used only once in the function signature. console.log(obj[key]); } " From cf26fa5293d3580e51ce9900670a7715c598b5d3 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Tue, 6 Aug 2024 14:33:54 -0400 Subject: [PATCH 2/3] Switch between class and function descriptor --- .../rules/no-unnecessary-type-parameters.ts | 86 ++++++++++-------- .../no-unnecessary-type-parameters.test.ts | 90 +++++++++---------- 2 files changed, 93 insertions(+), 83 deletions(-) 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 aa979d479dd6..3ea0321adf8c 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-parameters.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-parameters.ts @@ -21,7 +21,7 @@ export default createRule({ recommended: 'strict', }, messages: { - sole: 'Type parameter {{name}} is used only once in the function signature.', + sole: 'Type parameter {{name}} is used only once in the {{descriptor}} signature.', }, schema: [], type: 'problem', @@ -29,11 +29,49 @@ export default createRule({ name: 'no-unnecessary-type-parameters', create(context) { const parserServices = getParserServices(context); + + function checkNode(node: TSESTree.FunctionLike, descriptor: string): void { + const tsNode = parserServices.esTreeNodeToTSNodeMap.get( + node, + ) as NodeWithTypeParameters; + + const checker = parserServices.program.getTypeChecker(); + let counts: Map | undefined; + + for (const typeParameter of tsNode.typeParameters) { + const esTypeParameter = + parserServices.tsNodeToESTreeNodeMap.get( + typeParameter, + ); + const scope = context.sourceCode.getScope(esTypeParameter); + + // Quick path: if the type parameter is used multiple times in the AST, + // we don't need to dip into types to know it's repeated. + if (isTypeParameterRepeatedInAST(esTypeParameter, scope.references)) { + continue; + } + + // For any inferred types, we have to dip into type checking. + counts ??= countTypeParameterUsage(checker, tsNode); + const identifierCounts = counts.get(typeParameter.name); + if (!identifierCounts || identifierCounts > 2) { + continue; + } + + context.report({ + data: { + descriptor, + name: typeParameter.name.text, + }, + node: esTypeParameter, + messageId: 'sole', + }); + } + } + return { [[ 'ArrowFunctionExpression[typeParameters]', - 'ClassDeclaration[typeParameters]', - 'ClassExpression[typeParameters]', 'FunctionDeclaration[typeParameters]', 'FunctionExpression[typeParameters]', 'TSCallSignatureDeclaration[typeParameters]', @@ -43,41 +81,13 @@ export default createRule({ 'TSFunctionType[typeParameters]', 'TSMethodSignature[typeParameters]', ].join(', ')](node: TSESTree.FunctionLike): void { - const tsNode = parserServices.esTreeNodeToTSNodeMap.get( - node, - ) as NodeWithTypeParameters; - - const checker = parserServices.program.getTypeChecker(); - let counts: Map | undefined; - - for (const typeParameter of tsNode.typeParameters) { - const esTypeParameter = - parserServices.tsNodeToESTreeNodeMap.get( - typeParameter, - ); - const scope = context.sourceCode.getScope(esTypeParameter); - - // Quick path: if the type parameter is used multiple times in the AST, - // we don't need to dip into types to know it's repeated. - if (isTypeParameterRepeatedInAST(esTypeParameter, scope.references)) { - continue; - } - - // For any inferred types, we have to dip into type checking. - counts ??= countTypeParameterUsage(checker, tsNode); - const identifierCounts = counts.get(typeParameter.name); - if (!identifierCounts || identifierCounts > 2) { - continue; - } - - context.report({ - data: { - name: typeParameter.name.text, - }, - node: esTypeParameter, - messageId: 'sole', - }); - } + checkNode(node, 'function'); + }, + [[ + 'ClassDeclaration[typeParameters]', + 'ClassExpression[typeParameters]', + ].join(', ')](node: TSESTree.FunctionLike): void { + checkNode(node, 'class'); }, }; }, 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 e5a7558e2f49..6e89db7e2223 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 @@ -353,11 +353,11 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { invalid: [ { code: 'const func = (param: T) => null;', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: 'const f1 = (): T => {};', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: ` @@ -365,7 +365,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { (value: T): void; } `, - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: ` @@ -383,13 +383,13 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { } } `, - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'class', name: 'T' } }], }, { code: ` declare class C {} `, - errors: [{ messageId: 'sole', data: { name: 'V' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'class', name: 'V' } }], }, { code: ` @@ -398,8 +398,8 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { } `, errors: [ - { messageId: 'sole', data: { name: 'T' } }, - { messageId: 'sole', data: { name: 'U' } }, + { messageId: 'sole', data: { descriptor: 'class', name: 'T' } }, + { messageId: 'sole', data: { descriptor: 'class', name: 'U' } }, ], }, { @@ -409,8 +409,8 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { } `, errors: [ - { messageId: 'sole', data: { name: 'T' } }, - { messageId: 'sole', data: { name: 'U' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'T' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'U' } }, ], }, { @@ -419,7 +419,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { prop:

() => P; } `, - errors: [{ messageId: 'sole', data: { name: 'P' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'P' } }], }, { code: ` @@ -430,7 +430,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { errors: [ { messageId: 'sole', - data: { name: 'T' }, + data: { descriptor: 'function', name: 'T' }, }, ], }, @@ -441,8 +441,8 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { } `, errors: [ - { messageId: 'sole', data: { name: 'A' } }, - { messageId: 'sole', data: { name: 'B' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'A' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'B' } }, ], }, { @@ -451,7 +451,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { return input as any as T; } `, - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: ` @@ -459,7 +459,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { console.log(obj[key]); } `, - errors: [{ messageId: 'sole', data: { name: 'K' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'K' } }], }, { code: ` @@ -470,7 +470,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { `, errors: [ { - data: { name: 'T' }, + data: { descriptor: 'function', name: 'T' }, messageId: 'sole', }, ], @@ -489,8 +489,8 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { } `, errors: [ - { messageId: 'sole', data: { name: 'CB1' } }, - { messageId: 'sole', data: { name: 'CB2' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'CB1' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'CB2' } }, ], }, { @@ -514,105 +514,105 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { }, { code: 'declare function get(): T;', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: 'declare function get(): T;', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: 'declare function take(param: T): void;', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: 'declare function take(param: T): void;', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: 'declare function take(param1: T, param2: U): void;', - errors: [{ messageId: 'sole', data: { name: 'U' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U' } }], }, { code: 'declare function take(param: T): U;', - errors: [{ messageId: 'sole', data: { name: 'U' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U' } }], }, { code: 'declare function take(param: U): U;', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: 'declare function get(param: U): U;', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: 'declare function get(param: T): U;', - errors: [{ messageId: 'sole', data: { name: 'U' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U' } }], }, { code: 'declare function compare(param1: T, param2: U): boolean;', - errors: [{ messageId: 'sole', data: { name: 'U' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U' } }], }, { code: 'declare function get(param: (param: U) => V): T;', errors: [ - { messageId: 'sole', data: { name: 'T' } }, - { messageId: 'sole', data: { name: 'U' } }, - { messageId: 'sole', data: { name: 'V' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'T' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'U' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'V' } }, ], }, { code: 'declare function get(param: (param: T) => U): T;', errors: [ - { messageId: 'sole', data: { name: 'T' } }, - { messageId: 'sole', data: { name: 'T' } }, - { messageId: 'sole', data: { name: 'U' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'T' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'T' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'U' } }, ], }, { code: 'type Fn = () => T;', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: 'type Fn = () => [];', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: ` type Other = 0; type Fn = () => Other; `, - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: ` type Other = 0 | 1; type Fn = () => Other; `, - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: 'type Fn = (param: U) => void;', - errors: [{ messageId: 'sole', data: { name: 'U' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U' } }], }, { code: 'type Ctr = new () => T;', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: 'type Fn = () => { [K in keyof T]: K };', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: "type Fn = () => { [K in 'a']: T };", - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: 'type Fn = (value: unknown) => value is T;', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: 'type Fn = () => `a${T}b`;', - errors: [{ messageId: 'sole', data: { name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], }, { code: ` @@ -621,7 +621,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { fn: (key: K) => number, ): number[]; `, - errors: [{ messageId: 'sole', data: { name: 'V' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'V' } }], }, ], }); From d65f50e4bf13656bf63f3fa6608918388079b772 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 12 Aug 2024 00:09:56 -0400 Subject: [PATCH 3/3] special-case report for never-used parameters --- .../rules/no-unnecessary-type-parameters.mdx | 6 +- .../rules/no-unnecessary-type-parameters.ts | 7 +- .../no-unnecessary-type-parameters.test.ts | 98 ++++++++++--------- 3 files changed, 58 insertions(+), 53 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx b/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx index 79eb4b5d4936..a11969f58f51 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx @@ -1,5 +1,5 @@ --- -description: 'Disallow type parameters that only appear once.' +description: "Disallow type parameters that aren't used multiple times." --- import Tabs from '@theme/Tabs'; @@ -9,10 +9,10 @@ import TabItem from '@theme/TabItem'; > > See **https://typescript-eslint.io/rules/no-unnecessary-type-parameters** for documentation. -This rule forbids type parameters that only appear once in a function, method, or class definition. +This rule forbids type parameters that aren't used multiple times in a function, method, or class definition. Type parameters relate two types. -If a type parameter only appears once, then it is not relating anything. +If a type parameter is only used once, then it is not relating anything. It can usually be replaced with explicit types such as `unknown`. At best unnecessary type parameters make code harder to read. 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 3ea0321adf8c..f3304a58c06d 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-parameters.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-parameters.ts @@ -16,12 +16,12 @@ export default createRule({ defaultOptions: [], meta: { docs: { - description: 'Disallow type parameters that only appear once', + description: 'Disallow type parameters that aren\'t used multiple times', requiresTypeChecking: true, recommended: 'strict', }, messages: { - sole: 'Type parameter {{name}} is used only once in the {{descriptor}} signature.', + sole: 'Type parameter {{name}} is {{uses}} in the {{descriptor}} signature.', }, schema: [], type: 'problem', @@ -42,7 +42,7 @@ export default createRule({ const esTypeParameter = parserServices.tsNodeToESTreeNodeMap.get( typeParameter, - ); + ); const scope = context.sourceCode.getScope(esTypeParameter); // Quick path: if the type parameter is used multiple times in the AST, @@ -61,6 +61,7 @@ export default createRule({ context.report({ data: { descriptor, + uses: identifierCounts === 1 ? 'never used' : 'used only once', name: typeParameter.name.text, }, node: esTypeParameter, 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 6e89db7e2223..0651f33124e9 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 @@ -353,11 +353,11 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { invalid: [ { code: 'const func = (param: T) => null;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: 'const f1 = (): T => {};', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: ` @@ -365,7 +365,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { (value: T): void; } `, - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: ` @@ -383,13 +383,13 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { } } `, - errors: [{ messageId: 'sole', data: { descriptor: 'class', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'class', name: 'T', uses: 'used only once' } }], }, { code: ` declare class C {} `, - errors: [{ messageId: 'sole', data: { descriptor: 'class', name: 'V' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'class', name: 'V', uses: 'never used' } }], }, { code: ` @@ -398,8 +398,8 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { } `, errors: [ - { messageId: 'sole', data: { descriptor: 'class', name: 'T' } }, - { messageId: 'sole', data: { descriptor: 'class', name: 'U' } }, + { messageId: 'sole', data: { descriptor: 'class', name: 'T', uses: 'used only once' } }, + { messageId: 'sole', data: { descriptor: 'class', name: 'U', uses: 'used only once' } }, ], }, { @@ -409,8 +409,8 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { } `, errors: [ - { messageId: 'sole', data: { descriptor: 'function', name: 'T' } }, - { messageId: 'sole', data: { descriptor: 'function', name: 'U' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'U', uses: 'used only once' } }, ], }, { @@ -419,7 +419,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { prop:

() => P; } `, - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'P' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'P', uses: 'used only once' } }], }, { code: ` @@ -430,7 +430,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { errors: [ { messageId: 'sole', - data: { descriptor: 'function', name: 'T' }, + data: { descriptor: 'function', name: 'T', uses: 'used only once' }, }, ], }, @@ -441,8 +441,8 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { } `, errors: [ - { messageId: 'sole', data: { descriptor: 'function', name: 'A' } }, - { messageId: 'sole', data: { descriptor: 'function', name: 'B' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'A', uses: 'used only once' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'B', uses: 'used only once' } }, ], }, { @@ -451,7 +451,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { return input as any as T; } `, - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: ` @@ -459,7 +459,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { console.log(obj[key]); } `, - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'K' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'K', uses: 'used only once' } }], }, { code: ` @@ -470,7 +470,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { `, errors: [ { - data: { descriptor: 'function', name: 'T' }, + data: { descriptor: 'function', name: 'T', uses: 'used only once' }, messageId: 'sole', }, ], @@ -489,8 +489,8 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { } `, errors: [ - { messageId: 'sole', data: { descriptor: 'function', name: 'CB1' } }, - { messageId: 'sole', data: { descriptor: 'function', name: 'CB2' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'CB1', uses: 'used only once' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'CB2', uses: 'used only once' } }, ], }, { @@ -499,7 +499,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { return x.length; } `, - errors: [{ messageId: 'sole' }], + errors: [{ data: { descriptor: 'function', name: 'T', uses: 'used only once' }, messageId: 'sole', }], }, { code: ` @@ -510,109 +510,113 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { return x.length; } `, - errors: [{ messageId: 'sole' }], + errors: [{ data: { descriptor: 'function', name: 'T', uses: 'used only once' }, messageId: 'sole', }], + }, + { + code: 'declare function get(): unknown;', + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'never used' } }], }, { code: 'declare function get(): T;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: 'declare function get(): T;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: 'declare function take(param: T): void;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: 'declare function take(param: T): void;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: 'declare function take(param1: T, param2: U): void;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U', uses: 'used only once' } }], }, { code: 'declare function take(param: T): U;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U', uses: 'used only once' } }], }, { code: 'declare function take(param: U): U;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: 'declare function get(param: U): U;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: 'declare function get(param: T): U;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U', uses: 'used only once' } }], }, { code: 'declare function compare(param1: T, param2: U): boolean;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U', uses: 'used only once' } }], }, { code: 'declare function get(param: (param: U) => V): T;', errors: [ - { messageId: 'sole', data: { descriptor: 'function', name: 'T' } }, - { messageId: 'sole', data: { descriptor: 'function', name: 'U' } }, - { messageId: 'sole', data: { descriptor: 'function', name: 'V' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'U', uses: 'used only once' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'V', uses: 'used only once' } }, ], }, { code: 'declare function get(param: (param: T) => U): T;', errors: [ - { messageId: 'sole', data: { descriptor: 'function', name: 'T' } }, - { messageId: 'sole', data: { descriptor: 'function', name: 'T' } }, - { messageId: 'sole', data: { descriptor: 'function', name: 'U' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }, + { messageId: 'sole', data: { descriptor: 'function', name: 'U', uses: 'used only once' } }, ], }, { code: 'type Fn = () => T;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: 'type Fn = () => [];', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'never used' } }], }, { code: ` type Other = 0; type Fn = () => Other; `, - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'never used' } }], }, { code: ` type Other = 0 | 1; type Fn = () => Other; `, - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'never used' } }], }, { code: 'type Fn = (param: U) => void;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'U', uses: 'used only once' } }], }, { code: 'type Ctr = new () => T;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: 'type Fn = () => { [K in keyof T]: K };', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: "type Fn = () => { [K in 'a']: T };", - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: 'type Fn = (value: unknown) => value is T;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: 'type Fn = () => `a${T}b`;', - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'T', uses: 'used only once' } }], }, { code: ` @@ -621,7 +625,7 @@ ruleTester.run('no-unnecessary-type-parameters', rule, { fn: (key: K) => number, ): number[]; `, - errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'V' } }], + errors: [{ messageId: 'sole', data: { descriptor: 'function', name: 'V', uses: 'used only once' } }], }, ], }); 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