зеркало из https://github.com/microsoft/dtslint.git
Add `no-unnecessary-generics` rule
This commit is contained in:
Родитель
1fe792d227
Коммит
69d1595d49
|
@ -0,0 +1,62 @@
|
|||
# no-unnecessary-generics
|
||||
|
||||
Forbids a function to use a generic type parameter only once.
|
||||
Generic type parameters allow you to relate the type of one thing to another;
|
||||
if they are used only once, they can be replaced with their type constraint.
|
||||
|
||||
**Bad**:
|
||||
|
||||
```ts
|
||||
function logAnything<T>(x: T): void;
|
||||
```
|
||||
|
||||
**Good**:
|
||||
|
||||
```ts
|
||||
function logAnything(x: any): void;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Bad**:
|
||||
|
||||
```ts
|
||||
function useLogger<T extends Logger>(logger: T): void;
|
||||
```
|
||||
|
||||
**Good**:
|
||||
|
||||
```ts
|
||||
function useLogger(logger: Logger): void;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Bad**:
|
||||
|
||||
```ts
|
||||
function clear<T>(array: T[]): void;
|
||||
```
|
||||
|
||||
**Good**:
|
||||
|
||||
```ts
|
||||
function clear(array: any[]): void;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Bad**:
|
||||
|
||||
```ts
|
||||
function parse<T>(): T;
|
||||
const x = parse<number>();
|
||||
```
|
||||
|
||||
**Good**:
|
||||
|
||||
|
||||
```ts
|
||||
function parse(): {};
|
||||
const x = parse() as number;
|
||||
```
|
|
@ -12,6 +12,7 @@
|
|||
"strict-export-declare-modifiers": true,
|
||||
"no-any-union": true,
|
||||
"no-single-declare-module": true,
|
||||
"no-unnecessary-generics": true,
|
||||
"no-useless-files": true,
|
||||
"prefer-declare-function": true,
|
||||
"trim-file": true,
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
import * as Lint from "tslint";
|
||||
import * as ts from "typescript";
|
||||
|
||||
import { failure } from "../util";
|
||||
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
static metadata: Lint.IRuleMetadata = {
|
||||
ruleName: "no-unnecessary-generics",
|
||||
description: "Forbids signatures using a generic parameter only once.",
|
||||
optionsDescription: "Not configurable.",
|
||||
options: null,
|
||||
type: "style",
|
||||
typescriptOnly: true,
|
||||
};
|
||||
|
||||
static FAILURE_STRING(typeParameter: string) {
|
||||
return failure(
|
||||
Rule.metadata.ruleName,
|
||||
`Type parameter ${typeParameter} is used only once.`);
|
||||
}
|
||||
|
||||
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
return this.applyWithFunction(sourceFile, walk);
|
||||
}
|
||||
}
|
||||
|
||||
function walk(ctx: Lint.WalkContext<void>): void {
|
||||
const { sourceFile } = ctx;
|
||||
sourceFile.forEachChild(function cb(node) {
|
||||
if (ts.isFunctionLike(node)) {
|
||||
checkSignature(node);
|
||||
}
|
||||
node.forEachChild(cb);
|
||||
});
|
||||
|
||||
function checkSignature(sig: ts.SignatureDeclaration) {
|
||||
if (!sig.typeParameters) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const tp of sig.typeParameters) {
|
||||
const typeParameter = tp.name.text;
|
||||
const soleUse = getSoleUse(sig, typeParameter);
|
||||
if (soleUse !== undefined) {
|
||||
ctx.addFailureAtNode(soleUse, Rule.FAILURE_STRING(typeParameter));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getSoleUse(sig: ts.SignatureDeclaration, typeParameter: string): ts.Identifier | undefined {
|
||||
const exit = {};
|
||||
let soleUse: ts.Identifier | undefined;
|
||||
|
||||
try {
|
||||
for (const param of sig.parameters) {
|
||||
if (param.type) {
|
||||
recur(param.type);
|
||||
}
|
||||
}
|
||||
if (sig.type) {
|
||||
recur(sig.type);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err === exit) {
|
||||
return undefined;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
return soleUse;
|
||||
|
||||
function recur(node: ts.TypeNode) {
|
||||
if (ts.isIdentifier(node)) {
|
||||
if (node.text === typeParameter) {
|
||||
if (soleUse === undefined) {
|
||||
soleUse = node;
|
||||
} else {
|
||||
throw exit;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node.forEachChild(recur);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
interface I {
|
||||
<T>(value: T): void;
|
||||
~ [0]
|
||||
m<T>(x: T): void;
|
||||
~ [0]
|
||||
}
|
||||
|
||||
class C {
|
||||
constructor<T>(x: T) {}
|
||||
~ [0]
|
||||
}
|
||||
|
||||
type Fn = <T>() => T;
|
||||
~ [0]
|
||||
type Ctr = new<T>() => T;
|
||||
~ [0]
|
||||
|
||||
function f<T>(): T { }
|
||||
~ [0]
|
||||
|
||||
const f = function<T>(): T {};
|
||||
~ [0]
|
||||
const f2 = <T>(): T => {};
|
||||
~ [0]
|
||||
|
||||
// OK:
|
||||
function foo<T>(m: Map<T, T>): void {}
|
||||
|
||||
[0]: Type parameter T is used only once. See: https://github.com/Microsoft/dtslint/blob/master/docs/no-unnecessary-generics.md
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"rulesDirectory": ["../../bin/rules"],
|
||||
"rules": {
|
||||
"no-unnecessary-generics": true
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче