Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(eslint-plugin): [no-unnecessary-type-parameters] port from v8 to v7 #9473

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export default tseslint.config(
'error',
{ allowConstantLoopConditions: true },
],
'@typescript-eslint/no-unnecessary-type-parameters': 'error',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/prefer-literal-enum-member': [
'error',
Expand Down
115 changes: 115 additions & 0 deletions packages/eslint-plugin/docs/rules/no-unnecessary-type-parameters.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
description: 'Disallow type parameters that only appear once.'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

> 🛑 This file is source code, not the primary documentation location! 🛑
>
> 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.

Type parameters relate two types.
If a type parameter only appears 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.
At worst they can be used to disguise unsafe type assertions.

:::warning Early Stage
This rule was recently added to typescript-eslint and still considered experimental.
It might change significantly between minor versions.
Please try it out and give us feedback!
:::

## Examples

<Tabs>
<TabItem value="❌ Incorrect">

```ts
function second<A, B>(a: A, b: B): B {
return b;
}

function parseJSON<T>(input: string): T {
return JSON.parse(input);
}

function printProperty<T, K extends keyof T>(obj: T, key: K) {
console.log(obj[key]);
}
```

</TabItem>
<TabItem value="✅ Correct">

```ts
function second<B>(a: unknown, b: B): B {
return b;
}

function parseJSON(input: string): unknown {
return JSON.parse(input);
}

function printProperty<T>(obj: T, key: keyof T) {
console.log(obj[key]);
}

// T appears twice: in the type of arg and as the return type
function identity<T>(arg: T): T {
return arg;
}

// T appears twice: "keyof T" and in the inferred return type (T[K]).
// K appears twice: "key: K" and in the inferred return type (T[K]).
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
```

</TabItem>
</Tabs>

## Limitations

Note that this rule allows any type parameter that is used multiple times, even if those uses are via a type argument.
For example, the following `T` is used multiple times by virtue of being in an `Array`, even though its name only appears once after declaration:

```ts
declare function createStateHistory<T>(): T[];
```

This is because the type parameter `T` relates multiple methods in the `T[]` together, making it used more than once.

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`.

## When Not To Use It

This rule will report on functions that use type parameters solely to test types, for example:

```ts
function assertType<T>(arg: T) {}

assertType<number>(123);
assertType<number>('abc');
// ~~~~~
// Argument of type 'string' is not assignable to parameter of type 'number'.
```

If you're using this pattern then you'll want to disable this rule on files that test types.

## Further Reading

- TypeScript handbook: [Type Parameters Should Appear Twice](https://microsoft.github.io/TypeScript-New-Handbook/everything/#type-parameters-should-appear-twice)
- Effective TypeScript: [The Golden Rule of Generics](https://effectivetypescript.com/2020/08/12/generics-golden-rule/)

## Related To

- eslint-plugin-etc's [`no-misused-generics`](https://github.com/cartant/eslint-plugin-etc/blob/main/docs/rules/no-misused-generics.md)
- wotan's [`no-misused-generics`](https://github.com/fimbullinter/wotan/blob/master/packages/mimir/docs/no-misused-generics.md)
- DefinitelyTyped-tools' [`no-unnecessary-generics`](https://github.com/microsoft/DefinitelyTyped-tools/blob/main/packages/eslint-plugin/docs/rules/no-unnecessary-generics.md)
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/configs/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export = {
'@typescript-eslint/no-unnecessary-type-arguments': 'error',
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
'@typescript-eslint/no-unnecessary-type-constraint': 'error',
'@typescript-eslint/no-unnecessary-type-parameters': 'error',
'@typescript-eslint/no-unsafe-argument': 'error',
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/configs/disable-type-checked.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export = {
'@typescript-eslint/no-unnecessary-template-expression': 'off',
'@typescript-eslint/no-unnecessary-type-arguments': 'off',
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
'@typescript-eslint/no-unnecessary-type-parameters': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ import noUnnecessaryTemplateExpression from './no-unnecessary-template-expressio
import noUnnecessaryTypeArguments from './no-unnecessary-type-arguments';
import noUnnecessaryTypeAssertion from './no-unnecessary-type-assertion';
import noUnnecessaryTypeConstraint from './no-unnecessary-type-constraint';
import noUnnecessaryTypeParameters from './no-unnecessary-type-parameters';
import noUnsafeArgument from './no-unsafe-argument';
import noUnsafeAssignment from './no-unsafe-assignment';
import noUnsafeCall from './no-unsafe-call';
Expand Down Expand Up @@ -233,6 +234,7 @@ export default {
'no-unnecessary-type-arguments': noUnnecessaryTypeArguments,
'no-unnecessary-type-assertion': noUnnecessaryTypeAssertion,
'no-unnecessary-type-constraint': noUnnecessaryTypeConstraint,
'no-unnecessary-type-parameters': noUnnecessaryTypeParameters,
'no-unsafe-argument': noUnsafeArgument,
'no-unsafe-assignment': noUnsafeAssignment,
'no-unsafe-call': noUnsafeCall,
Expand Down
Loading
Loading