@definitelytyped/dtslint 0.0.141 → 0.0.142-next.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/rules/no-any-union.d.ts +4 -0
  2. package/dist/rules/no-any-union.js +34 -0
  3. package/dist/rules/no-any-union.js.map +1 -0
  4. package/dist/rules/no-unnecessary-generics.d.ts +8 -0
  5. package/dist/rules/no-unnecessary-generics.js +135 -0
  6. package/dist/rules/no-unnecessary-generics.js.map +1 -0
  7. package/dist/rules/prefer-declare-function.d.ts +5 -0
  8. package/dist/rules/prefer-declare-function.js +35 -0
  9. package/dist/rules/prefer-declare-function.js.map +1 -0
  10. package/dtslint.json +0 -3
  11. package/package.json +3 -3
  12. package/src/rules/no-any-union.ts +34 -0
  13. package/src/rules/no-unnecessary-generics.ts +126 -0
  14. package/src/rules/prefer-declare-function.ts +37 -0
  15. package/test/no-any-union.test.ts +22 -0
  16. package/test/no-unnecessary-generics.test.ts +152 -0
  17. package/test/prefer-declare-function.test.ts +66 -0
  18. package/test/tsconfig.json +8 -0
  19. package/tsconfig.tsbuildinfo +1 -1
  20. package/dist/rules/noAnyUnionRule.d.ts +0 -7
  21. package/dist/rules/noAnyUnionRule.js +0 -53
  22. package/dist/rules/noAnyUnionRule.js.map +0 -1
  23. package/dist/rules/noUnnecessaryGenericsRule.d.ts +0 -8
  24. package/dist/rules/noUnnecessaryGenericsRule.js +0 -134
  25. package/dist/rules/noUnnecessaryGenericsRule.js.map +0 -1
  26. package/dist/rules/preferDeclareFunctionRule.d.ts +0 -7
  27. package/dist/rules/preferDeclareFunctionRule.js +0 -56
  28. package/dist/rules/preferDeclareFunctionRule.js.map +0 -1
  29. package/src/rules/noAnyUnionRule.ts +0 -33
  30. package/src/rules/noUnnecessaryGenericsRule.ts +0 -115
  31. package/src/rules/preferDeclareFunctionRule.ts +0 -36
  32. package/test/no-any-union/test.d.ts.lint +0 -4
  33. package/test/no-any-union/tslint.json +0 -6
  34. package/test/no-unnecessary-generics/test.ts.lint +0 -38
  35. package/test/no-unnecessary-generics/tsconfig.json +0 -1
  36. package/test/no-unnecessary-generics/tslint.json +0 -6
  37. package/test/prefer-declare-function/test.d.ts.lint +0 -10
  38. package/test/prefer-declare-function/tslint.json +0 -6
@@ -0,0 +1,4 @@
1
+ declare const rule: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"anyUnion", never[], {
2
+ TSUnionType(node: import("@typescript-eslint/types/dist/generated/ast-spec").TSUnionType): void;
3
+ }>;
4
+ export = rule;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ const util_1 = require("../util");
3
+ const utils_1 = require("@typescript-eslint/utils");
4
+ const rule = (0, util_1.createRule)({
5
+ name: "no-any-union",
6
+ defaultOptions: [],
7
+ meta: {
8
+ type: "problem",
9
+ docs: {
10
+ description: "Forbid a union to contain `any`",
11
+ recommended: "error",
12
+ },
13
+ messages: {
14
+ anyUnion: "Including `any` in a union will override all other members of the union.",
15
+ },
16
+ schema: [],
17
+ },
18
+ create(context) {
19
+ return {
20
+ // eslint-disable-next-line @typescript-eslint/naming-convention
21
+ TSUnionType(node) {
22
+ const hasAnyType = node.types.some((t) => t.type === utils_1.AST_NODE_TYPES.TSAnyKeyword);
23
+ if (hasAnyType) {
24
+ context.report({
25
+ messageId: "anyUnion",
26
+ node,
27
+ });
28
+ }
29
+ },
30
+ };
31
+ },
32
+ });
33
+ module.exports = rule;
34
+ //# sourceMappingURL=no-any-union.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-any-union.js","sourceRoot":"","sources":["../../src/rules/no-any-union.ts"],"names":[],"mappings":";AAAA,kCAAqC;AACrC,oDAA0D;AAE1D,MAAM,IAAI,GAAG,IAAA,iBAAU,EAAC;IACtB,IAAI,EAAE,cAAc;IACpB,cAAc,EAAE,EAAE;IAClB,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,iCAAiC;YAC9C,WAAW,EAAE,OAAO;SACrB;QACD,QAAQ,EAAE;YACR,QAAQ,EAAE,0EAA0E;SACrF;QACD,MAAM,EAAE,EAAE;KACX;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,gEAAgE;YAChE,WAAW,CAAC,IAAI;gBACd,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,sBAAc,CAAC,YAAY,CAAC,CAAC;gBAClF,IAAI,UAAU,EAAE;oBACd,OAAO,CAAC,MAAM,CAAC;wBACb,SAAS,EAAE,UAAU;wBACrB,IAAI;qBACL,CAAC,CAAC;iBACJ;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC;AAEH,iBAAS,IAAI,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { TSESTree } from "@typescript-eslint/utils";
2
+ declare type ESTreeFunctionLikeWithTypeParameters = TSESTree.FunctionLike & {
3
+ typeParameters: {};
4
+ };
5
+ declare const rule: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"never" | "sole", never[], {
6
+ [x: string]: (esNode: ESTreeFunctionLikeWithTypeParameters) => void;
7
+ }>;
8
+ export = rule;
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ const utils_1 = require("@typescript-eslint/utils");
26
+ const ts = __importStar(require("typescript"));
27
+ const util_1 = require("../util");
28
+ const rule = (0, util_1.createRule)({
29
+ defaultOptions: [],
30
+ meta: {
31
+ docs: {
32
+ description: "Forbids signatures using a generic parameter only once.",
33
+ recommended: "error",
34
+ },
35
+ messages: {
36
+ never: "Type parameter {{name}} is never used.",
37
+ sole: "Type parameter {{name}} is used only once.",
38
+ },
39
+ schema: [],
40
+ type: "problem",
41
+ },
42
+ name: "no-relative-import-in-test",
43
+ create(context) {
44
+ return {
45
+ [[
46
+ "ArrowFunctionExpression[typeParameters]",
47
+ "FunctionDeclaration[typeParameters]",
48
+ "FunctionExpression[typeParameters]",
49
+ "TSCallSignatureDeclaration[typeParameters]",
50
+ "TSConstructorType[typeParameters]",
51
+ "TSDeclareFunction[typeParameters]",
52
+ "TSFunctionType[typeParameters]",
53
+ "TSMethodSignature[typeParameters]",
54
+ ].join(", ")](esNode) {
55
+ const parserServices = utils_1.ESLintUtils.getParserServices(context);
56
+ const tsNode = parserServices.esTreeNodeToTSNodeMap.get(esNode);
57
+ if (!tsNode.typeParameters) {
58
+ return;
59
+ }
60
+ const checker = parserServices.program.getTypeChecker();
61
+ for (const typeParameter of tsNode.typeParameters) {
62
+ const name = typeParameter.name.text;
63
+ const res = getSoleUse(tsNode, assertDefined(checker.getSymbolAtLocation(typeParameter.name)), checker);
64
+ switch (res.type) {
65
+ case "sole":
66
+ context.report({
67
+ data: { name },
68
+ messageId: "sole",
69
+ node: parserServices.tsNodeToESTreeNodeMap.get(res.soleUse),
70
+ });
71
+ break;
72
+ case "never":
73
+ context.report({
74
+ data: { name },
75
+ messageId: "never",
76
+ node: parserServices.tsNodeToESTreeNodeMap.get(typeParameter),
77
+ });
78
+ break;
79
+ }
80
+ }
81
+ },
82
+ };
83
+ },
84
+ });
85
+ function getSoleUse(sig, typeParameterSymbol, checker) {
86
+ const exit = {};
87
+ let soleUse;
88
+ try {
89
+ if (sig.typeParameters) {
90
+ for (const tp of sig.typeParameters) {
91
+ if (tp.constraint) {
92
+ recur(tp.constraint);
93
+ }
94
+ }
95
+ }
96
+ for (const param of sig.parameters) {
97
+ if (param.type) {
98
+ recur(param.type);
99
+ }
100
+ }
101
+ if (sig.type) {
102
+ recur(sig.type);
103
+ }
104
+ }
105
+ catch (err) {
106
+ if (err === exit) {
107
+ return { type: "ok" };
108
+ }
109
+ throw err;
110
+ }
111
+ return soleUse ? { type: "sole", soleUse } : { type: "never" };
112
+ function recur(node) {
113
+ if (ts.isIdentifier(node)) {
114
+ if (checker.getSymbolAtLocation(node) === typeParameterSymbol) {
115
+ if (soleUse === undefined) {
116
+ soleUse = node;
117
+ }
118
+ else {
119
+ throw exit;
120
+ }
121
+ }
122
+ }
123
+ else {
124
+ node.forEachChild(recur);
125
+ }
126
+ }
127
+ }
128
+ function assertDefined(value) {
129
+ if (value === undefined) {
130
+ throw new Error("unreachable");
131
+ }
132
+ return value;
133
+ }
134
+ module.exports = rule;
135
+ //# sourceMappingURL=no-unnecessary-generics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-unnecessary-generics.js","sourceRoot":"","sources":["../../src/rules/no-unnecessary-generics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { TSESTree } from "@typescript-eslint/utils";
2
+ declare const rule: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"variableFunction", never[], {
3
+ "VariableDeclaration > VariableDeclarator"(node: TSESTree.VariableDeclarator): void;
4
+ }>;
5
+ export = rule;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ const utils_1 = require("@typescript-eslint/utils");
3
+ const util_1 = require("../util");
4
+ const rule = (0, util_1.createRule)({
5
+ defaultOptions: [],
6
+ meta: {
7
+ docs: {
8
+ description: "Forbids `const x: () => void`.",
9
+ recommended: "error",
10
+ },
11
+ messages: {
12
+ variableFunction: "Use a function declaration instead of a variable of function type.",
13
+ },
14
+ schema: [],
15
+ type: "problem",
16
+ },
17
+ name: "prefer-declare-function",
18
+ create(context) {
19
+ return {
20
+ // eslint-disable-next-line @typescript-eslint/naming-convention
21
+ "VariableDeclaration > VariableDeclarator"(node) {
22
+ var _a;
23
+ if (((_a = node.id.typeAnnotation) === null || _a === void 0 ? void 0 : _a.typeAnnotation.type) === utils_1.AST_NODE_TYPES.TSFunctionType &&
24
+ context.getFilename().endsWith(".d.ts")) {
25
+ context.report({
26
+ messageId: "variableFunction",
27
+ node: node.id,
28
+ });
29
+ }
30
+ },
31
+ };
32
+ },
33
+ });
34
+ module.exports = rule;
35
+ //# sourceMappingURL=prefer-declare-function.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefer-declare-function.js","sourceRoot":"","sources":["../../src/rules/prefer-declare-function.ts"],"names":[],"mappings":";AAAA,oDAAoE;AAEpE,kCAAqC;AAErC,MAAM,IAAI,GAAG,IAAA,iBAAU,EAAC;IACtB,cAAc,EAAE,EAAE;IAClB,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,WAAW,EAAE,gCAAgC;YAC7C,WAAW,EAAE,OAAO;SACrB;QACD,QAAQ,EAAE;YACR,gBAAgB,EAAE,oEAAoE;SACvF;QACD,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,SAAS;KAChB;IACD,IAAI,EAAE,yBAAyB;IAC/B,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,gEAAgE;YAChE,0CAA0C,CAAC,IAAiC;;gBAC1E,IACE,CAAA,MAAA,IAAI,CAAC,EAAE,CAAC,cAAc,0CAAE,cAAc,CAAC,IAAI,MAAK,sBAAc,CAAC,cAAc;oBAC7E,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EACvC;oBACA,OAAO,CAAC,MAAM,CAAC;wBACb,SAAS,EAAE,kBAAkB;wBAC7B,IAAI,EAAE,IAAI,CAAC,EAAE;qBACd,CAAC,CAAC;iBACJ;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC;AAEH,iBAAS,IAAI,CAAC"}
package/dtslint.json CHANGED
@@ -9,10 +9,7 @@
9
9
  "redundant-undefined": true,
10
10
  "no-relative-import-in-test": true,
11
11
  "strict-export-declare-modifiers": true,
12
- "no-any-union": true,
13
12
  "no-single-declare-module": true,
14
- "no-unnecessary-generics": true,
15
- "prefer-declare-function": true,
16
13
  "unified-signatures": true,
17
14
  "void-return": true,
18
15
  "npm-naming": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@definitelytyped/dtslint",
3
- "version": "0.0.141",
3
+ "version": "0.0.142-next.12",
4
4
  "description": "Runs tests on TypeScript definition files",
5
5
  "main": "./dist/index.js",
6
6
  "bin": "./dist/index.js",
@@ -44,11 +44,11 @@
44
44
  "@types/fs-extra": "^5.0.2",
45
45
  "@types/json-stable-stringify": "^1.0.32",
46
46
  "@types/strip-json-comments": "^0.0.28",
47
- "typescript": "next"
47
+ "typescript": "4.7.4"
48
48
  },
49
49
  "engines": {
50
50
  "node": ">=10.0.0"
51
51
  },
52
52
  "license": "MIT",
53
- "gitHead": "60e42f914dcfb07c5072de0c0aebaeac34b596e4"
53
+ "gitHead": "ada755591d9e6980cfdcb69ce9e2e7c740378384"
54
54
  }
@@ -0,0 +1,34 @@
1
+ import { createRule } from "../util";
2
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
3
+
4
+ const rule = createRule({
5
+ name: "no-any-union",
6
+ defaultOptions: [],
7
+ meta: {
8
+ type: "problem",
9
+ docs: {
10
+ description: "Forbid a union to contain `any`",
11
+ recommended: "error",
12
+ },
13
+ messages: {
14
+ anyUnion: "Including `any` in a union will override all other members of the union.",
15
+ },
16
+ schema: [],
17
+ },
18
+ create(context) {
19
+ return {
20
+ // eslint-disable-next-line @typescript-eslint/naming-convention
21
+ TSUnionType(node) {
22
+ const hasAnyType = node.types.some((t) => t.type === AST_NODE_TYPES.TSAnyKeyword);
23
+ if (hasAnyType) {
24
+ context.report({
25
+ messageId: "anyUnion",
26
+ node,
27
+ });
28
+ }
29
+ },
30
+ };
31
+ },
32
+ });
33
+
34
+ export = rule;
@@ -0,0 +1,126 @@
1
+ import { ESLintUtils, TSESTree } from "@typescript-eslint/utils";
2
+ import * as ts from "typescript";
3
+
4
+ import { createRule } from "../util";
5
+
6
+ type ESTreeFunctionLikeWithTypeParameters = TSESTree.FunctionLike & {
7
+ typeParameters: {};
8
+ };
9
+
10
+ type TSSignatureDeclarationWithTypeParameters = ts.SignatureDeclaration & {
11
+ typeParameters: {};
12
+ };
13
+
14
+ const rule = createRule({
15
+ defaultOptions: [],
16
+ meta: {
17
+ docs: {
18
+ description: "Forbids signatures using a generic parameter only once.",
19
+ recommended: "error",
20
+ },
21
+ messages: {
22
+ never: "Type parameter {{name}} is never used.",
23
+ sole: "Type parameter {{name}} is used only once.",
24
+ },
25
+ schema: [],
26
+ type: "problem",
27
+ },
28
+ name: "no-relative-import-in-test",
29
+ create(context) {
30
+ return {
31
+ [[
32
+ "ArrowFunctionExpression[typeParameters]",
33
+ "FunctionDeclaration[typeParameters]",
34
+ "FunctionExpression[typeParameters]",
35
+ "TSCallSignatureDeclaration[typeParameters]",
36
+ "TSConstructorType[typeParameters]",
37
+ "TSDeclareFunction[typeParameters]",
38
+ "TSFunctionType[typeParameters]",
39
+ "TSMethodSignature[typeParameters]",
40
+ ].join(", ")](esNode: ESTreeFunctionLikeWithTypeParameters) {
41
+ const parserServices = ESLintUtils.getParserServices(context);
42
+ const tsNode = parserServices.esTreeNodeToTSNodeMap.get(esNode) as TSSignatureDeclarationWithTypeParameters;
43
+ if (!tsNode.typeParameters) {
44
+ return;
45
+ }
46
+
47
+ const checker = parserServices.program.getTypeChecker();
48
+
49
+ for (const typeParameter of tsNode.typeParameters) {
50
+ const name = typeParameter.name.text;
51
+ const res = getSoleUse(tsNode, assertDefined(checker.getSymbolAtLocation(typeParameter.name)), checker);
52
+ switch (res.type) {
53
+ case "sole":
54
+ context.report({
55
+ data: { name },
56
+ messageId: "sole",
57
+ node: parserServices.tsNodeToESTreeNodeMap.get(res.soleUse),
58
+ });
59
+ break;
60
+ case "never":
61
+ context.report({
62
+ data: { name },
63
+ messageId: "never",
64
+ node: parserServices.tsNodeToESTreeNodeMap.get(typeParameter),
65
+ });
66
+ break;
67
+ }
68
+ }
69
+ },
70
+ };
71
+ },
72
+ });
73
+
74
+ type Result = { type: "ok" | "never" } | { type: "sole"; soleUse: ts.Identifier };
75
+ function getSoleUse(sig: ts.SignatureDeclaration, typeParameterSymbol: ts.Symbol, checker: ts.TypeChecker): Result {
76
+ const exit = {};
77
+ let soleUse: ts.Identifier | undefined;
78
+
79
+ try {
80
+ if (sig.typeParameters) {
81
+ for (const tp of sig.typeParameters) {
82
+ if (tp.constraint) {
83
+ recur(tp.constraint);
84
+ }
85
+ }
86
+ }
87
+ for (const param of sig.parameters) {
88
+ if (param.type) {
89
+ recur(param.type);
90
+ }
91
+ }
92
+ if (sig.type) {
93
+ recur(sig.type);
94
+ }
95
+ } catch (err) {
96
+ if (err === exit) {
97
+ return { type: "ok" };
98
+ }
99
+ throw err;
100
+ }
101
+
102
+ return soleUse ? { type: "sole", soleUse } : { type: "never" };
103
+
104
+ function recur(node: ts.Node): void {
105
+ if (ts.isIdentifier(node)) {
106
+ if (checker.getSymbolAtLocation(node) === typeParameterSymbol) {
107
+ if (soleUse === undefined) {
108
+ soleUse = node;
109
+ } else {
110
+ throw exit;
111
+ }
112
+ }
113
+ } else {
114
+ node.forEachChild(recur);
115
+ }
116
+ }
117
+ }
118
+
119
+ export = rule;
120
+
121
+ function assertDefined<T>(value: T | undefined): T {
122
+ if (value === undefined) {
123
+ throw new Error("unreachable");
124
+ }
125
+ return value;
126
+ }
@@ -0,0 +1,37 @@
1
+ import { AST_NODE_TYPES, TSESTree } from "@typescript-eslint/utils";
2
+
3
+ import { createRule } from "../util";
4
+
5
+ const rule = createRule({
6
+ defaultOptions: [],
7
+ meta: {
8
+ docs: {
9
+ description: "Forbids `const x: () => void`.",
10
+ recommended: "error",
11
+ },
12
+ messages: {
13
+ variableFunction: "Use a function declaration instead of a variable of function type.",
14
+ },
15
+ schema: [],
16
+ type: "problem",
17
+ },
18
+ name: "prefer-declare-function",
19
+ create(context) {
20
+ return {
21
+ // eslint-disable-next-line @typescript-eslint/naming-convention
22
+ "VariableDeclaration > VariableDeclarator"(node: TSESTree.VariableDeclarator) {
23
+ if (
24
+ node.id.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES.TSFunctionType &&
25
+ context.getFilename().endsWith(".d.ts")
26
+ ) {
27
+ context.report({
28
+ messageId: "variableFunction",
29
+ node: node.id,
30
+ });
31
+ }
32
+ },
33
+ };
34
+ },
35
+ });
36
+
37
+ export = rule;
@@ -0,0 +1,22 @@
1
+ import { ESLintUtils } from "@typescript-eslint/utils";
2
+
3
+ import * as noAnyUnion from "../src/rules/no-any-union";
4
+
5
+ const ruleTester = new ESLintUtils.RuleTester({
6
+ parser: "@typescript-eslint/parser",
7
+ });
8
+
9
+ ruleTester.run("no-any-union", noAnyUnion, {
10
+ invalid: [
11
+ {
12
+ code: `export const y: string | any;`,
13
+ errors: [
14
+ {
15
+ line: 1,
16
+ messageId: "anyUnion",
17
+ },
18
+ ],
19
+ },
20
+ ],
21
+ valid: [`export const x: any;`],
22
+ });
@@ -0,0 +1,152 @@
1
+ import { ESLintUtils } from "@typescript-eslint/utils";
2
+
3
+ import * as rule from "../src/rules/no-unnecessary-generics";
4
+
5
+ const ruleTester = new ESLintUtils.RuleTester({
6
+ parserOptions: {
7
+ ecmaVersion: 2018,
8
+ tsconfigRootDir: __dirname,
9
+ project: "./tsconfig.json",
10
+ },
11
+ parser: "@typescript-eslint/parser",
12
+ });
13
+
14
+ ruleTester.run("no-unnecessary-generics", rule, {
15
+ invalid: [
16
+ {
17
+ code: `
18
+ const f2 = <T>(): T => {};
19
+ `,
20
+ errors: [
21
+ {
22
+ line: 2,
23
+ column: 19,
24
+ messageId: "sole",
25
+ },
26
+ ],
27
+ },
28
+ {
29
+ code: `
30
+ class C {
31
+ constructor<T>(x: T) {}
32
+ }
33
+ `,
34
+ errors: [
35
+ {
36
+ line: 3,
37
+ column: 21,
38
+ messageId: "sole",
39
+ },
40
+ ],
41
+ },
42
+ {
43
+ code: `
44
+ function f<T>(): T { }
45
+ `,
46
+ errors: [
47
+ {
48
+ line: 2,
49
+ column: 18,
50
+ messageId: "sole",
51
+ },
52
+ ],
53
+ },
54
+ {
55
+ code: `
56
+ function f<T>(x: { T: number }): void;
57
+ `,
58
+ errors: [
59
+ {
60
+ line: 2,
61
+ column: 12,
62
+ messageId: "never",
63
+ },
64
+ ],
65
+ },
66
+ {
67
+ code: `
68
+ function f<T, U extends T>(u: U): U;
69
+ `,
70
+ errors: [
71
+ {
72
+ line: 2,
73
+ column: 25,
74
+ messageId: "sole",
75
+ },
76
+ ],
77
+ },
78
+ {
79
+ code: `
80
+ const f = function<T>(): T {};
81
+ `,
82
+ errors: [
83
+ {
84
+ line: 2,
85
+ column: 26,
86
+ messageId: "sole",
87
+ },
88
+ ],
89
+ },
90
+ {
91
+ code: `
92
+ interface I {
93
+ <T>(value: T): void;
94
+ }
95
+ `,
96
+ errors: [
97
+ {
98
+ line: 3,
99
+ column: 14,
100
+ messageId: "sole",
101
+ },
102
+ ],
103
+ },
104
+ {
105
+ code: `
106
+ interface I {
107
+ m<T>(x: T): void;
108
+ }
109
+ `,
110
+ errors: [
111
+ {
112
+ line: 3,
113
+ column: 11,
114
+ messageId: "sole",
115
+ },
116
+ ],
117
+ },
118
+ {
119
+ code: `
120
+ type Fn = <T>() => T;
121
+ `,
122
+ errors: [
123
+ {
124
+ line: 2,
125
+ column: 20,
126
+ messageId: "sole",
127
+ },
128
+ ],
129
+ },
130
+ {
131
+ code: `
132
+ type Ctr = new<T>() => T;
133
+ `,
134
+ errors: [
135
+ {
136
+ line: 2,
137
+ column: 24,
138
+ messageId: "sole",
139
+ },
140
+ ],
141
+ },
142
+ ],
143
+ valid: [
144
+ `function example(a: string): string;`,
145
+ `function example<T>(a: T): T;`,
146
+ `function example<T>(a: T[]): T;`,
147
+ `function example<T>(a: Set<T>): T;`,
148
+ `function example<T>(a: Set<T>, b: T[]): void;`,
149
+ `function example<T>(a: Map<T, T>): void;`,
150
+ `function example<T, U extends T>(t: T, u: U): U;`,
151
+ ],
152
+ });