From 88115e81e31e7b9da0d26397a20251ee713d5ce4 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Thu, 12 Sep 2024 00:11:58 -0600 Subject: [PATCH 01/12] [no-unnecessary-type-parameters] add FAQ section --- .../rules/no-unnecessary-type-parameters.mdx | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) 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 a11969f58f51..f9e2e0e03a25 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx @@ -87,6 +87,106 @@ This is because the type parameter `T` relates multiple methods in the `T[]` tog Therefore, this rule won't report on type parameters used as a type argument. That includes type arguments given to global types such as `Array` (including the `T[]` shorthand and in tuples), `Map`, and `Set`. +## FAQ + +### I'm using the type parameter inside the function, so why is the rule reporting? + +You might be surprised to that the rule reports on a function like this: + +```ts +function f(string1: T): void { + const string2: T = string1; + console.log(string2); +} +``` + +After all, the type parameter `T` relates the input `string1` and the local variable `string2`, right? +However, this usage is unnecessary, since we can achieve the same results by replacing all usages of the type parameter with its constraint. +That is to say, the function can always be rewritten as: + +```ts +function f(string1: string): void { + const string2: string = string1; + console.log(string2); +} +``` + +Therefore, this rule only counts usages of a type parameter in the _signature_ of a function, method, or class, but not in the implementation. + +### Why am I getting TypeScript errors saying "Object literal may only specify known properties" after removing an unnecessary type parameter? + +Suppose you have a situation like the following, which will trigger the rule to report. + +```ts +interface SomeProperties { + foo: string; +} + +// T is only used once, so the rule will report. +function serialize(x: T): string { + return JSON.stringify(x); +} + +serialize({ foo: 'bar', anotherProperty: 'baz' }); +``` + +If we remove the unnecessary type parameter, we'll get an error: + +```ts +function serialize(x: SomeProperties): string { + return JSON.stringify(x); +} + +// TS Error: Object literal may only specify known properties, and 'anotherProperty' does not exist in type 'SomeProperties'. +serialize({ foo: 'bar', anotherProperty: 'baz' }); +``` + +This is because TypeScript figures it's _usually_ an error to explicitly provide excess properties in a location that expects a specific type. +See [the TypeScript handbook's section on excess property checks](https://www.typescriptlang.org/docs/handbook/2/objects.html#excess-property-checks) for further discussion. + +The bottom line is - if it doesn't make sense to accept excess properties in your function, congrats! +You've found a bug in your code, and you can remove the excess property from the call site. +Otherwise, if you do want your function to accept excess properties, you can modify the parameter type in order to allow excess properties explicitly by using an [index signature](https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures): + +```ts +interface SomeProperties { + foo: string; + + // This allows any other properties. + // You may wish to make these types more specific according to your use case. + [key: PropertKey]: unknown; +} + +function serialize(x: SomeProperties): string { + return JSON.stringify(x); +} + +// No error! +serialize({ foo: 'bar', anotherProperty: 'baz' }); +``` + +Which solution is appropriate is a case-by-case decision, depending on the intended use case of your function. + +### I have a complex scenario that is reported by the rule, but I can't see how to remove the type parameter. What should I do? + +Sometimes, you may be able to rewrite the code by reaching for some niche TypeScript features, such as [the `NoInfer` utility type](https://www.typescriptlang.org/docs/handbook/utility-types.html#noinfertype) (see [#9751](https://github.com/typescript-eslint/typescript-eslint/issues/9751)). + +But, quite possibly, you've hit an edge case where the type is being used in a subtle way that the rule doesn't account for. +For example, the following code is a way of testing that two types are equal, and currently will be reported by the rule (see [#9709](https://github.com/typescript-eslint/typescript-eslint/issues/9709)): + +```ts +type Equal = + (() => T1 extends Compute ? 1 : 2) extends < + T2, + >() => T2 extends Compute ? 1 : 2 + ? true + : false; +``` + +Use eslint-disable comments as appropriate to suppress the rule in these cases. + +{/* TODO - include an FAQ entry regarding instantiation expressions once the conversation in https://github.com/typescript-eslint/typescript-eslint/pull/9536#discussion_r1705850744 is done */} + ## When Not To Use It This rule will report on functions that use type parameters solely to test types, for example: From c782be1fcf73e618c0dafaeb43a3fe2b556112e0 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Thu, 12 Sep 2024 00:30:34 -0600 Subject: [PATCH 02/12] wording --- .../docs/rules/no-unnecessary-type-parameters.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 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 f9e2e0e03a25..35d5bad93701 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx @@ -144,8 +144,8 @@ serialize({ foo: 'bar', anotherProperty: 'baz' }); This is because TypeScript figures it's _usually_ an error to explicitly provide excess properties in a location that expects a specific type. See [the TypeScript handbook's section on excess property checks](https://www.typescriptlang.org/docs/handbook/2/objects.html#excess-property-checks) for further discussion. -The bottom line is - if it doesn't make sense to accept excess properties in your function, congrats! -You've found a bug in your code, and you can remove the excess property from the call site. +To resolve this, you have two choices. If it doesn't make sense to accept excess properties in your function, congrats! +You've found a potential bug in your code, and you can remove the excess property from the call site. Otherwise, if you do want your function to accept excess properties, you can modify the parameter type in order to allow excess properties explicitly by using an [index signature](https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures): ```ts From 9cc7d6607a9c132bfdbd778ba290fdd3cd58d4fa Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Thu, 12 Sep 2024 00:36:54 -0600 Subject: [PATCH 03/12] wording --- .../rules/no-unnecessary-type-parameters.mdx | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 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 35d5bad93701..b25c657cb135 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx @@ -144,26 +144,27 @@ serialize({ foo: 'bar', anotherProperty: 'baz' }); This is because TypeScript figures it's _usually_ an error to explicitly provide excess properties in a location that expects a specific type. See [the TypeScript handbook's section on excess property checks](https://www.typescriptlang.org/docs/handbook/2/objects.html#excess-property-checks) for further discussion. -To resolve this, you have two choices. If it doesn't make sense to accept excess properties in your function, congrats! -You've found a potential bug in your code, and you can remove the excess property from the call site. -Otherwise, if you do want your function to accept excess properties, you can modify the parameter type in order to allow excess properties explicitly by using an [index signature](https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures): +To resolve this, you have two approaches to choose from. -```ts -interface SomeProperties { - foo: string; +1. If it doesn't make sense to accept excess properties in your function, you'll want to fix the errors at the call sites. Usually, you can simply remove any excess properties where the function is called. +2. Otherwise, if you do want your function to accept excess properties, you can modify the parameter type in order to allow excess properties explicitly by using an [index signature](https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures): - // This allows any other properties. - // You may wish to make these types more specific according to your use case. - [key: PropertKey]: unknown; -} + ```ts + interface SomeProperties { + foo: string; -function serialize(x: SomeProperties): string { - return JSON.stringify(x); -} + // This allows any other properties. + // You may wish to make these types more specific according to your use case. + [key: PropertKey]: unknown; + } -// No error! -serialize({ foo: 'bar', anotherProperty: 'baz' }); -``` + function serialize(x: SomeProperties): string { + return JSON.stringify(x); + } + + // No error! + serialize({ foo: 'bar', anotherProperty: 'baz' }); + ``` Which solution is appropriate is a case-by-case decision, depending on the intended use case of your function. From d6282cebaf3086342f3eac54aaeaa3e4a7c523d9 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Thu, 12 Sep 2024 00:39:31 -0600 Subject: [PATCH 04/12] update admonition link --- .../eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b25c657cb135..a71b7558a462 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx @@ -19,7 +19,7 @@ At best unnecessary type parameters make code harder to read. At worst they can be used to disguise unsafe type assertions. :::warning -This rule was recently added, and has a surprising amount of hidden complexity compared to most of our rules. If you encounter unexpected behavior with it, please check closely the [Limitations](#limitations) section below and our [issue tracker](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+no-unnecessary-type-parameters). +This rule was recently added, and has a surprising amount of hidden complexity compared to most of our rules. If you encounter unexpected behavior with it, please check closely the [Limitations](#limitations) and [FAQ](#faq) sections below and our [issue tracker](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+no-unnecessary-type-parameters). If you don't see your case covered, please [reach out to us](https://typescript-eslint.io/contributing/issues)! ::: From 18f111ec9f7ccf2e235408b79c5fb6c4f8415bf3 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Thu, 12 Sep 2024 00:45:53 -0600 Subject: [PATCH 05/12] test case --- .../no-unnecessary-type-parameters.test.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) 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 ebc7a9ec181c..e183e0a7e7dc 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 @@ -961,5 +961,31 @@ declare function sillyFoo( }, ], }, + { + // This isn't actually an important test case. + // However, we use it as an example in the docs of code that is flagged, + // but shouldn't necessarily be. So, if you make change to the rule logic + // that "resolve" this sort-of-false-positive, please update the docs + // accordingly. + // Originally discussion in https://github.com/typescript-eslint/typescript-eslint/issues/9709 + code: ` +type Equal = + (() => T1 extends Compute ? 1 : 2) extends < + T2, + >() => T2 extends Compute ? 1 : 2 + ? true + : false; + `, + errors: [ + { + messageId: 'sole', + data: { descriptor: 'function', name: 'T1', uses: 'used only once' }, + }, + { + messageId: 'sole', + data: { descriptor: 'function', name: 'T2', uses: 'used only once' }, + }, + ], + }, ], }); From 12f5ec13d087ac352fa14985c4334b00214dc441 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Thu, 12 Sep 2024 12:04:45 -0600 Subject: [PATCH 06/12] stuf --- .../docs/rules/no-unnecessary-type-parameters.mdx | 13 +++++++------ .../rules/no-unnecessary-type-parameters.test.ts | 6 +++--- 2 files changed, 10 insertions(+), 9 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 a71b7558a462..f02d1549e550 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx @@ -173,15 +173,16 @@ Which solution is appropriate is a case-by-case decision, depending on the inten Sometimes, you may be able to rewrite the code by reaching for some niche TypeScript features, such as [the `NoInfer` utility type](https://www.typescriptlang.org/docs/handbook/utility-types.html#noinfertype) (see [#9751](https://github.com/typescript-eslint/typescript-eslint/issues/9751)). But, quite possibly, you've hit an edge case where the type is being used in a subtle way that the rule doesn't account for. -For example, the following code is a way of testing that two types are equal, and currently will be reported by the rule (see [#9709](https://github.com/typescript-eslint/typescript-eslint/issues/9709)): +For example, the following arcane code is a way of testing that two types are equal, and currently will be reported by the rule (see [#9709](https://github.com/typescript-eslint/typescript-eslint/issues/9709)): +{/* prettier-ignore */} ```ts +type Compute = A extends Function ? A : { [K in keyof A]: Compute }; type Equal = - (() => T1 extends Compute ? 1 : 2) extends < - T2, - >() => T2 extends Compute ? 1 : 2 - ? true - : false; + (() => T1 extends Compute ? 1 : 2) extends + (() => T2 extends Compute ? 1 : 2) + ? true + : false; ``` Use eslint-disable comments as appropriate to suppress the rule in these cases. 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 e183e0a7e7dc..dd683b7d9fec 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 @@ -964,10 +964,10 @@ declare function sillyFoo( { // This isn't actually an important test case. // However, we use it as an example in the docs of code that is flagged, - // but shouldn't necessarily be. So, if you make change to the rule logic - // that "resolve" this sort-of-false-positive, please update the docs + // but shouldn't necessarily be. So, if you make a change to the rule logic + // that resolves this sort-of-false-positive, please update the docs // accordingly. - // Originally discussion in https://github.com/typescript-eslint/typescript-eslint/issues/9709 + // Original discussion in https://github.com/typescript-eslint/typescript-eslint/issues/9709 code: ` type Equal = (() => T1 extends Compute ? 1 : 2) extends < From d235591353989c2770ea2504a47be68aef37ae38 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Thu, 12 Sep 2024 12:06:36 -0600 Subject: [PATCH 07/12] prettierer --- .../docs/rules/no-unnecessary-type-parameters.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 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 f02d1549e550..0210ffc528b9 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx @@ -181,8 +181,8 @@ type Compute = A extends Function ? A : { [K in keyof A]: Compute }; type Equal = (() => T1 extends Compute ? 1 : 2) extends (() => T2 extends Compute ? 1 : 2) - ? true - : false; + ? true + : false; ``` Use eslint-disable comments as appropriate to suppress the rule in these cases. From 5c4aa67bac3e640acf530ddec0af929c9d67d402 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Thu, 12 Sep 2024 12:07:52 -0600 Subject: [PATCH 08/12] test case formatting --- .../rules/no-unnecessary-type-parameters.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 dd683b7d9fec..200baa533d04 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 @@ -1,4 +1,4 @@ -import { RuleTester } from '@typescript-eslint/rule-tester'; +import { noFormat, RuleTester } from '@typescript-eslint/rule-tester'; import rule from '../../src/rules/no-unnecessary-type-parameters'; import { getFixturesRootDir } from '../RuleTester'; @@ -968,13 +968,13 @@ declare function sillyFoo( // that resolves this sort-of-false-positive, please update the docs // accordingly. // Original discussion in https://github.com/typescript-eslint/typescript-eslint/issues/9709 - code: ` + code: noFormat` +type Compute = A extends Function ? A : { [K in keyof A]: Compute }; type Equal = - (() => T1 extends Compute ? 1 : 2) extends < - T2, - >() => T2 extends Compute ? 1 : 2 - ? true - : false; + (() => T1 extends Compute ? 1 : 2) extends + (() => T2 extends Compute ? 1 : 2) + ? true + : false; `, errors: [ { From b712e2a27904e2ba07e9a59cca3dbafe30450f76 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Thu, 12 Sep 2024 16:58:08 -0600 Subject: [PATCH 09/12] log --- .../docs/rules/no-unnecessary-type-parameters.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 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 0210ffc528b9..d8585300bd1a 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx @@ -94,7 +94,7 @@ That includes type arguments given to global types such as `Array` (including th You might be surprised to that the rule reports on a function like this: ```ts -function f(string1: T): void { +function log(string1: T): void { const string2: T = string1; console.log(string2); } @@ -105,7 +105,7 @@ However, this usage is unnecessary, since we can achieve the same results by rep That is to say, the function can always be rewritten as: ```ts -function f(string1: string): void { +function log(string1: string): void { const string2: string = string1; console.log(string2); } From 3fee06500bac2d35abbc5bf886b3938e80d23473 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Fri, 13 Sep 2024 15:41:52 -0600 Subject: [PATCH 10/12] mention 9735 --- .../eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d8585300bd1a..03396abbffbd 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx @@ -111,7 +111,7 @@ function log(string1: string): void { } ``` -Therefore, this rule only counts usages of a type parameter in the _signature_ of a function, method, or class, but not in the implementation. +Therefore, this rule only counts usages of a type parameter in the _signature_ of a function, method, or class, but not in the implementation. See also [#9735](https://github.com/typescript-eslint/typescript-eslint/issues/9735) ### Why am I getting TypeScript errors saying "Object literal may only specify known properties" after removing an unnecessary type parameter? From 023241fe27ff642d341ef7a03e0ef0a69f3a7c6d Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Fri, 13 Sep 2024 15:56:14 -0600 Subject: [PATCH 11/12] explain the equal false positives a little better --- .../docs/rules/no-unnecessary-type-parameters.mdx | 7 +++++-- 1 file changed, 5 insertions(+), 2 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 03396abbffbd..03bf8e87c0f4 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx @@ -173,7 +173,7 @@ Which solution is appropriate is a case-by-case decision, depending on the inten Sometimes, you may be able to rewrite the code by reaching for some niche TypeScript features, such as [the `NoInfer` utility type](https://www.typescriptlang.org/docs/handbook/utility-types.html#noinfertype) (see [#9751](https://github.com/typescript-eslint/typescript-eslint/issues/9751)). But, quite possibly, you've hit an edge case where the type is being used in a subtle way that the rule doesn't account for. -For example, the following arcane code is a way of testing that two types are equal, and currently will be reported by the rule (see [#9709](https://github.com/typescript-eslint/typescript-eslint/issues/9709)): +For example, the following arcane code is a way of testing whether two types are equal, and will be reported by the rule (see [#9709](https://github.com/typescript-eslint/typescript-eslint/issues/9709)): {/* prettier-ignore */} ```ts @@ -185,7 +185,10 @@ type Equal = : false; ``` -Use eslint-disable comments as appropriate to suppress the rule in these cases. +In this case, the function types created within the `Equal` type are never expected to be assigned to; they're just created for the purpose of type system manipulations. +This usage is not what the rule is intended to analyze. + +Use eslint-disable comments as appropriate to suppress the rule in these kinds of cases. {/* TODO - include an FAQ entry regarding instantiation expressions once the conversation in https://github.com/typescript-eslint/typescript-eslint/pull/9536#discussion_r1705850744 is done */} From 88aa43fbad91df1ca4808a9fddb040120c8a2164 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Thu, 19 Sep 2024 13:18:39 -0600 Subject: [PATCH 12/12] add implicit return type FAQ --- .../rules/no-unnecessary-type-parameters.mdx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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 03bf8e87c0f4..c27da7616a0f 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx @@ -89,6 +89,22 @@ That includes type arguments given to global types such as `Array` (including th ## FAQ +### The return type is only used as an input, so why isn't the rule reporting? + +One common reason that this might be the case is when the return type is not specified explicitly. +The rule uses uses type information to count implicit usages of the type parameter in the function signature, including in the inferred return type. +For example, the following function... + +```ts +function identity(arg: T) { + return arg; +} +``` + +...implicitly has a return type of `T`. Therefore, the type parameter `T` is used twice, and the rule will not report this function. + +For other reasons the rule might not be reporting, be sure to check the [Limitations section](#limitations) and other FAQs. + ### I'm using the type parameter inside the function, so why is the rule reporting? You might be surprised to that the rule reports on a function like this: