eslint-plugin-typefest 1.0.6 → 1.0.8
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.
- package/README.md +107 -91
- package/dist/_internal/constrained-type-at-location.d.ts.map +1 -1
- package/dist/_internal/constrained-type-at-location.js.map +1 -1
- package/dist/_internal/function-type-reference-patterns.d.ts +34 -0
- package/dist/_internal/function-type-reference-patterns.d.ts.map +1 -0
- package/dist/_internal/function-type-reference-patterns.js +103 -0
- package/dist/_internal/function-type-reference-patterns.js.map +1 -0
- package/dist/_internal/rule-catalog.d.ts.map +1 -1
- package/dist/_internal/rule-catalog.js +11 -0
- package/dist/_internal/rule-catalog.js.map +1 -1
- package/dist/_internal/rules-registry.d.ts.map +1 -1
- package/dist/_internal/rules-registry.js +22 -0
- package/dist/_internal/rules-registry.js.map +1 -1
- package/dist/_internal/set-membership.d.ts.map +1 -1
- package/dist/_internal/set-membership.js.map +1 -1
- package/dist/_internal/type-checker-compat.d.ts.map +1 -1
- package/dist/_internal/type-checker-compat.js.map +1 -1
- package/dist/_internal/type-reference-node.d.ts +8 -0
- package/dist/_internal/type-reference-node.d.ts.map +1 -1
- package/dist/_internal/type-reference-node.js +14 -0
- package/dist/_internal/type-reference-node.js.map +1 -1
- package/dist/_internal/typefest-config-references.d.ts +2 -1
- package/dist/_internal/typefest-config-references.d.ts.map +1 -1
- package/dist/_internal/typefest-config-references.js +11 -2
- package/dist/_internal/typefest-config-references.js.map +1 -1
- package/dist/_internal/typescript-eslint-node-autofix.js.map +1 -1
- package/dist/plugin.cjs +1077 -124
- package/dist/plugin.cjs.map +4 -4
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +5 -0
- package/dist/plugin.js.map +1 -1
- package/dist/rules/prefer-ts-extras-object-map-values.d.ts +14 -0
- package/dist/rules/prefer-ts-extras-object-map-values.d.ts.map +1 -0
- package/dist/rules/prefer-ts-extras-object-map-values.js +227 -0
- package/dist/rules/prefer-ts-extras-object-map-values.js.map +1 -0
- package/dist/rules/prefer-type-fest-asyncify.d.ts +7 -0
- package/dist/rules/prefer-type-fest-asyncify.d.ts.map +1 -0
- package/dist/rules/prefer-type-fest-asyncify.js +79 -0
- package/dist/rules/prefer-type-fest-asyncify.js.map +1 -0
- package/dist/rules/prefer-type-fest-conditional-except.d.ts +7 -0
- package/dist/rules/prefer-type-fest-conditional-except.d.ts.map +1 -0
- package/dist/rules/prefer-type-fest-conditional-except.js +94 -0
- package/dist/rules/prefer-type-fest-conditional-except.js.map +1 -0
- package/dist/rules/prefer-type-fest-conditional-keys.d.ts +7 -0
- package/dist/rules/prefer-type-fest-conditional-keys.d.ts.map +1 -0
- package/dist/rules/prefer-type-fest-conditional-keys.js +78 -0
- package/dist/rules/prefer-type-fest-conditional-keys.js.map +1 -0
- package/dist/rules/prefer-type-fest-distributed-omit.d.ts +7 -0
- package/dist/rules/prefer-type-fest-distributed-omit.d.ts.map +1 -0
- package/dist/rules/prefer-type-fest-distributed-omit.js +67 -0
- package/dist/rules/prefer-type-fest-distributed-omit.js.map +1 -0
- package/dist/rules/prefer-type-fest-distributed-pick.d.ts +7 -0
- package/dist/rules/prefer-type-fest-distributed-pick.d.ts.map +1 -0
- package/dist/rules/prefer-type-fest-distributed-pick.js +95 -0
- package/dist/rules/prefer-type-fest-distributed-pick.js.map +1 -0
- package/dist/rules/prefer-type-fest-merge.d.ts +7 -0
- package/dist/rules/prefer-type-fest-merge.d.ts.map +1 -0
- package/dist/rules/prefer-type-fest-merge.js +93 -0
- package/dist/rules/prefer-type-fest-merge.js.map +1 -0
- package/dist/rules/prefer-type-fest-pick-index-signature.d.ts +7 -0
- package/dist/rules/prefer-type-fest-pick-index-signature.d.ts.map +1 -0
- package/dist/rules/prefer-type-fest-pick-index-signature.js +98 -0
- package/dist/rules/prefer-type-fest-pick-index-signature.js.map +1 -0
- package/dist/rules/prefer-type-fest-set-return-type.d.ts +7 -0
- package/dist/rules/prefer-type-fest-set-return-type.d.ts.map +1 -0
- package/dist/rules/prefer-type-fest-set-return-type.js +53 -0
- package/dist/rules/prefer-type-fest-set-return-type.js.map +1 -0
- package/dist/rules/prefer-type-fest-stringified.d.ts +7 -0
- package/dist/rules/prefer-type-fest-stringified.d.ts.map +1 -0
- package/dist/rules/prefer-type-fest-stringified.js +73 -0
- package/dist/rules/prefer-type-fest-stringified.js.map +1 -0
- package/dist/rules/prefer-type-fest-union-to-intersection.d.ts +7 -0
- package/dist/rules/prefer-type-fest-union-to-intersection.d.ts.map +1 -0
- package/dist/rules/prefer-type-fest-union-to-intersection.js +114 -0
- package/dist/rules/prefer-type-fest-union-to-intersection.js.map +1 -0
- package/docs/rules/getting-started.md +2 -1
- package/docs/rules/guides/preset-selection-strategy.md +7 -0
- package/docs/rules/overview.md +1 -0
- package/docs/rules/prefer-ts-extras-object-map-values.md +146 -0
- package/docs/rules/prefer-type-fest-asyncify.md +93 -0
- package/docs/rules/prefer-type-fest-conditional-except.md +141 -0
- package/docs/rules/prefer-type-fest-conditional-keys.md +93 -0
- package/docs/rules/prefer-type-fest-distributed-omit.md +92 -0
- package/docs/rules/prefer-type-fest-distributed-pick.md +92 -0
- package/docs/rules/prefer-type-fest-merge.md +161 -0
- package/docs/rules/prefer-type-fest-pick-index-signature.md +93 -0
- package/docs/rules/prefer-type-fest-set-return-type.md +93 -0
- package/docs/rules/prefer-type-fest-stringified.md +134 -0
- package/docs/rules/prefer-type-fest-union-to-intersection.md +118 -0
- package/docs/rules/presets/experimental.md +163 -0
- package/docs/rules/presets/index.md +13 -0
- package/package.json +33 -34
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { areEquivalentTypeNodes } from "../_internal/normalize-expression-text.js";
|
|
2
|
+
import { reportWithOptionalFix } from "../_internal/rule-reporting.js";
|
|
3
|
+
import { unwrapParenthesizedTypeNode } from "../_internal/type-reference-node.js";
|
|
4
|
+
import { createTypedRule } from "../_internal/typed-rule.js";
|
|
5
|
+
const isDistributiveConditionalExtendsType = (node) => {
|
|
6
|
+
const normalizedNode = unwrapParenthesizedTypeNode(node);
|
|
7
|
+
return (normalizedNode.type === "TSAnyKeyword" ||
|
|
8
|
+
normalizedNode.type === "TSUnknownKeyword");
|
|
9
|
+
};
|
|
10
|
+
const getSingleFunctionParameterType = (node) => {
|
|
11
|
+
if (node.params.length !== 1) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const [onlyParameter] = node.params;
|
|
15
|
+
if (onlyParameter?.type !== "Identifier" ||
|
|
16
|
+
onlyParameter.typeAnnotation === undefined) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return unwrapParenthesizedTypeNode(onlyParameter.typeAnnotation.typeAnnotation);
|
|
20
|
+
};
|
|
21
|
+
const matchesUnionToIntersectionTrueType = (node, inferredTypeParameterName, unionType) => {
|
|
22
|
+
const normalizedNode = unwrapParenthesizedTypeNode(node);
|
|
23
|
+
if (normalizedNode.type === "TSTypeReference" &&
|
|
24
|
+
normalizedNode.typeName.type === "Identifier" &&
|
|
25
|
+
normalizedNode.typeName.name === inferredTypeParameterName) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
if (normalizedNode.type !== "TSIntersectionType" ||
|
|
29
|
+
normalizedNode.types.length !== 2) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const [leftType, rightType] = normalizedNode.types;
|
|
33
|
+
if (leftType === undefined || rightType === undefined) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const isInferredIdentifier = (typeNode) => typeNode.type === "TSTypeReference" &&
|
|
37
|
+
typeNode.typeName.type === "Identifier" &&
|
|
38
|
+
typeNode.typeName.name === inferredTypeParameterName;
|
|
39
|
+
return ((isInferredIdentifier(leftType) &&
|
|
40
|
+
areEquivalentTypeNodes(unwrapParenthesizedTypeNode(rightType), unwrapParenthesizedTypeNode(unionType))) ||
|
|
41
|
+
(isInferredIdentifier(rightType) &&
|
|
42
|
+
areEquivalentTypeNodes(unwrapParenthesizedTypeNode(leftType), unwrapParenthesizedTypeNode(unionType))));
|
|
43
|
+
};
|
|
44
|
+
const isUnionToIntersectionEquivalent = (node) => {
|
|
45
|
+
if (node.falseType.type !== "TSNeverKeyword") {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const distributedWrapper = unwrapParenthesizedTypeNode(node.checkType);
|
|
49
|
+
if (distributedWrapper.type !== "TSConditionalType") {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (distributedWrapper.falseType.type !== "TSNeverKeyword" ||
|
|
53
|
+
!isDistributiveConditionalExtendsType(distributedWrapper.extendsType)) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const distributedTrueType = unwrapParenthesizedTypeNode(distributedWrapper.trueType);
|
|
57
|
+
if (distributedTrueType.type !== "TSFunctionType") {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
const distributedParameterType = getSingleFunctionParameterType(distributedTrueType);
|
|
61
|
+
if (distributedParameterType === null ||
|
|
62
|
+
!areEquivalentTypeNodes(distributedParameterType, unwrapParenthesizedTypeNode(distributedWrapper.checkType))) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
const extractorFunctionType = unwrapParenthesizedTypeNode(node.extendsType);
|
|
66
|
+
if (extractorFunctionType.type !== "TSFunctionType") {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
const extractorParameterType = getSingleFunctionParameterType(extractorFunctionType);
|
|
70
|
+
if (extractorParameterType?.type !== "TSInferType") {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return matchesUnionToIntersectionTrueType(node.trueType, extractorParameterType.typeParameter.name.name, distributedWrapper.checkType);
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* ESLint rule definition for `prefer-type-fest-union-to-intersection`.
|
|
77
|
+
*/
|
|
78
|
+
const preferTypeFestUnionToIntersectionRule = createTypedRule({
|
|
79
|
+
create(context) {
|
|
80
|
+
return {
|
|
81
|
+
TSConditionalType(node) {
|
|
82
|
+
if (!isUnionToIntersectionEquivalent(node)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
reportWithOptionalFix({
|
|
86
|
+
context,
|
|
87
|
+
fix: null,
|
|
88
|
+
messageId: "preferUnionToIntersection",
|
|
89
|
+
node,
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
},
|
|
94
|
+
defaultOptions: [],
|
|
95
|
+
meta: {
|
|
96
|
+
deprecated: false,
|
|
97
|
+
docs: {
|
|
98
|
+
description: "require TypeFest UnionToIntersection over custom distributive conditional helpers that turn unions into intersections.",
|
|
99
|
+
frozen: false,
|
|
100
|
+
recommended: false,
|
|
101
|
+
requiresTypeChecking: false,
|
|
102
|
+
typefestConfigs: ["typefest.configs.experimental"],
|
|
103
|
+
url: "https://nick2bad4u.github.io/eslint-plugin-typefest/docs/rules/prefer-type-fest-union-to-intersection",
|
|
104
|
+
},
|
|
105
|
+
messages: {
|
|
106
|
+
preferUnionToIntersection: "Prefer `UnionToIntersection<Union>` from type-fest over custom distributive conditional helpers that convert a union into an intersection.",
|
|
107
|
+
},
|
|
108
|
+
schema: [],
|
|
109
|
+
type: "suggestion",
|
|
110
|
+
},
|
|
111
|
+
name: "prefer-type-fest-union-to-intersection",
|
|
112
|
+
});
|
|
113
|
+
export default preferTypeFestUnionToIntersectionRule;
|
|
114
|
+
//# sourceMappingURL=prefer-type-fest-union-to-intersection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer-type-fest-union-to-intersection.js","sourceRoot":"","sources":["../../src/rules/prefer-type-fest-union-to-intersection.ts"],"names":[],"mappings":"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"}
|
|
@@ -64,7 +64,8 @@ Use this pattern when you only extend rules and want full control over parser se
|
|
|
64
64
|
2. Fix violations in small batches.
|
|
65
65
|
3. Move to `recommended-type-checked` when you are ready for typed rules.
|
|
66
66
|
4. Move to `strict` once your baseline is stable.
|
|
67
|
-
5. Use `all`
|
|
67
|
+
5. Use `all` when you want every stable rule.
|
|
68
|
+
6. Use `experimental` only when you want report-only candidate rules under active evaluation.
|
|
68
69
|
|
|
69
70
|
## Need a subset instead of a full preset?
|
|
70
71
|
|
|
@@ -53,6 +53,13 @@ Choose this when:
|
|
|
53
53
|
- You want full plugin coverage and can manage incremental cleanup.
|
|
54
54
|
- You actively maintain migration and suppression hygiene.
|
|
55
55
|
|
|
56
|
+
### `experimental`
|
|
57
|
+
|
|
58
|
+
Choose this when:
|
|
59
|
+
|
|
60
|
+
- You want everything from `all` plus lower-confidence candidate rules.
|
|
61
|
+
- You are comfortable evaluating report-only diagnostics before broader rollout.
|
|
62
|
+
|
|
56
63
|
### Domain overlays
|
|
57
64
|
|
|
58
65
|
Layer these when they match your codebase goals:
|
package/docs/rules/overview.md
CHANGED
|
@@ -39,6 +39,7 @@ That is enough for TypeScript files (`**/*.{ts,tsx,mts,cts}`).
|
|
|
39
39
|
| 🟠 `typefest.configs["recommended-type-checked"]` | [Recommended (type-checked)](./presets/recommended-type-checked.md) |
|
|
40
40
|
| 🔴 `typefest.configs.strict` | [Strict](./presets/strict.md) |
|
|
41
41
|
| 🟣 `typefest.configs.all` | [All](./presets/all.md) |
|
|
42
|
+
| 🧪 `typefest.configs.experimental` | [Experimental](./presets/experimental.md) |
|
|
42
43
|
| 💠 `typefest.configs["type-fest/types"]` | [type-fest/types](./presets/type-fest-types.md) |
|
|
43
44
|
| ✴️ `typefest.configs["ts-extras/type-guards"]` | [ts-extras/type-guards](./presets/ts-extras-type-guards.md) |
|
|
44
45
|
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# prefer-ts-extras-object-map-values
|
|
2
|
+
|
|
3
|
+
Prefer [`objectMapValues`](https://github.com/sindresorhus/ts-extras/blob/main/source/object-map-values.ts) from `ts-extras` over key-preserving `objectFromEntries(objectEntries(...).map(...))` chains.
|
|
4
|
+
|
|
5
|
+
This rule lives only in the experimental preset and reports without autofixing.
|
|
6
|
+
|
|
7
|
+
## Targeted pattern scope
|
|
8
|
+
|
|
9
|
+
This rule focuses on `ts-extras` entry pipelines whose callback preserves the original key and only changes the value.
|
|
10
|
+
|
|
11
|
+
- `objectFromEntries(objectEntries(value).map(([key, item]) => [key, nextValue]))`
|
|
12
|
+
- the same shape with a block body that immediately returns `[key, nextValue]`
|
|
13
|
+
|
|
14
|
+
It intentionally skips broader patterns that can encode different intent.
|
|
15
|
+
|
|
16
|
+
## What this rule reports
|
|
17
|
+
|
|
18
|
+
This rule reports ts-extras object remapping chains when all of the following are true:
|
|
19
|
+
|
|
20
|
+
- the outer call is `objectFromEntries(...)`
|
|
21
|
+
- the inner source is `objectEntries(...)`
|
|
22
|
+
- the intermediate step is a direct `.map(...)` call
|
|
23
|
+
- the callback is an arrow function with a strict `[key, value]` tuple parameter
|
|
24
|
+
- the callback returns a two-item tuple whose first item is the original `key`
|
|
25
|
+
|
|
26
|
+
The rule is currently **report-only**. It does not autofix or suggest a replacement yet.
|
|
27
|
+
|
|
28
|
+
## Why this rule exists
|
|
29
|
+
|
|
30
|
+
`objectMapValues` reduces noise in a common value-only remapping pattern.
|
|
31
|
+
|
|
32
|
+
- The callback contract matches the intent directly: `(value, key) => nextValue`.
|
|
33
|
+
- Readers do not need to mentally unpack an entries pipeline to see that keys stay the same.
|
|
34
|
+
- The code avoids a temporary array of tuples in authored source.
|
|
35
|
+
|
|
36
|
+
Because this pattern appears in semantically different forms, the rule stays narrow on purpose and reports only equivalent key-preserving remaps.
|
|
37
|
+
|
|
38
|
+
## ❌ Incorrect
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import {objectEntries, objectFromEntries} from "ts-extras";
|
|
42
|
+
|
|
43
|
+
const statusById = {
|
|
44
|
+
alpha: "up",
|
|
45
|
+
beta: "down",
|
|
46
|
+
} as const;
|
|
47
|
+
|
|
48
|
+
const labels = objectFromEntries(
|
|
49
|
+
objectEntries(statusById).map(([key, value]) => [key, `${key}:${value}`])
|
|
50
|
+
);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## ✅ Correct
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import {objectMapValues} from "ts-extras";
|
|
57
|
+
|
|
58
|
+
const statusById = {
|
|
59
|
+
alpha: "up",
|
|
60
|
+
beta: "down",
|
|
61
|
+
} as const;
|
|
62
|
+
|
|
63
|
+
const labels = objectMapValues(
|
|
64
|
+
statusById,
|
|
65
|
+
(value, key) => `${key}:${value}`
|
|
66
|
+
);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Behavior and migration notes
|
|
70
|
+
|
|
71
|
+
- This rule only reports chains that preserve the original key unchanged.
|
|
72
|
+
- It ignores native `Object.entries` / `Object.fromEntries` pipelines to avoid overlapping with the stable `objectEntries` and `objectFromEntries` adoption rules.
|
|
73
|
+
- It ignores `.map(...)` calls that pass a `thisArg`, because `objectMapValues` does not have an equivalent callback binding parameter.
|
|
74
|
+
- It ignores function-expression callbacks for now, because the experimental rule avoids assuming `this` behavior is irrelevant.
|
|
75
|
+
|
|
76
|
+
## Additional examples
|
|
77
|
+
|
|
78
|
+
### ❌ Incorrect — Additional example
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import {objectEntries, objectFromEntries} from "ts-extras";
|
|
82
|
+
|
|
83
|
+
const statusById = {
|
|
84
|
+
alpha: "up",
|
|
85
|
+
beta: "down",
|
|
86
|
+
} as const;
|
|
87
|
+
|
|
88
|
+
const uppercased = objectFromEntries(
|
|
89
|
+
objectEntries(statusById).map(([key, value]) => [key, value.toUpperCase()])
|
|
90
|
+
);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### ✅ Correct — Additional example
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import {objectMapValues} from "ts-extras";
|
|
97
|
+
|
|
98
|
+
const statusById = {
|
|
99
|
+
alpha: "up",
|
|
100
|
+
beta: "down",
|
|
101
|
+
} as const;
|
|
102
|
+
|
|
103
|
+
const uppercased = objectMapValues(statusById, (value) => value.toUpperCase());
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## ESLint flat config example
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import typefest from "eslint-plugin-typefest";
|
|
110
|
+
|
|
111
|
+
export default [typefest.configs.experimental];
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## When not to use it
|
|
115
|
+
|
|
116
|
+
Disable this rule if your team prefers explicit entry-tuple pipelines for readability, or if the remapping logic changes keys often enough that `objectMapValues` is not the dominant style.
|
|
117
|
+
|
|
118
|
+
## Package documentation
|
|
119
|
+
|
|
120
|
+
ts-extras package documentation:
|
|
121
|
+
|
|
122
|
+
Source file: [`source/object-map-values.ts`](https://github.com/sindresorhus/ts-extras/blob/main/source/object-map-values.ts)
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import {objectMapValues} from "ts-extras";
|
|
126
|
+
|
|
127
|
+
const object = {a: 1, b: 2, c: 3};
|
|
128
|
+
|
|
129
|
+
const mapped = objectMapValues(object, value => String(value));
|
|
130
|
+
//=> {a?: string; b?: string; c?: string}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
> **Rule catalog ID:** R086
|
|
134
|
+
|
|
135
|
+
## Further reading
|
|
136
|
+
|
|
137
|
+
- [`ts-extras` README](https://github.com/sindresorhus/ts-extras)
|
|
138
|
+
- [`ts-extras` package reference](https://www.npmjs.com/package/ts-extras)
|
|
139
|
+
- [MDN: Array.prototype.map()](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
|
|
140
|
+
- [MDN: Object.fromEntries()](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries)
|
|
141
|
+
|
|
142
|
+
## Adoption resources
|
|
143
|
+
|
|
144
|
+
- [Rule adoption checklist](./guides/adoption-checklist.md)
|
|
145
|
+
- [Rollout and fix safety](./guides/rollout-and-fix-safety.md)
|
|
146
|
+
- [Preset selection strategy](./guides/preset-selection-strategy.md)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# prefer-type-fest-asyncify
|
|
2
|
+
|
|
3
|
+
Prefer [`Asyncify`](https://github.com/sindresorhus/type-fest/blob/main/source/asyncify.d.ts) from `type-fest` over manual asyncified function-type wrappers.
|
|
4
|
+
|
|
5
|
+
This rule lives only in the experimental preset and reports without autofixing.
|
|
6
|
+
|
|
7
|
+
## Targeted pattern scope
|
|
8
|
+
|
|
9
|
+
This rule focuses on two narrow shapes:
|
|
10
|
+
|
|
11
|
+
- direct function-type wrappers of the form `(...args: Parameters<Function>) => Promise<Awaited<ReturnType<Function>>>`
|
|
12
|
+
- `SetReturnType<Function, Promise<Awaited<ReturnType<Function>>>>` compositions
|
|
13
|
+
|
|
14
|
+
It intentionally skips broader promise-returning wrappers so the report signal stays specific to `Asyncify`.
|
|
15
|
+
|
|
16
|
+
## What this rule reports
|
|
17
|
+
|
|
18
|
+
This rule reports when all of the following are true:
|
|
19
|
+
|
|
20
|
+
- the wrapper keeps the original parameter list through `Parameters<Function>` or `SetReturnType<Function, ...>`
|
|
21
|
+
- the new return type is exactly `Promise<Awaited<ReturnType<Function>>>`
|
|
22
|
+
|
|
23
|
+
The rule is currently **report-only**. It does not autofix or suggest a replacement yet.
|
|
24
|
+
|
|
25
|
+
## Why this rule exists
|
|
26
|
+
|
|
27
|
+
`Asyncify<Function>` communicates the intent directly.
|
|
28
|
+
|
|
29
|
+
- Readers can tell immediately that a synchronous function type is being boxed into an async equivalent.
|
|
30
|
+
- The helper avoids repeating the `Promise<Awaited<ReturnType<...>>>` boilerplate.
|
|
31
|
+
- It composes naturally with other Type-Fest function helpers.
|
|
32
|
+
|
|
33
|
+
## ❌ Incorrect
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
type AsyncVersion<Function_ extends (...arguments_: any[]) => any> =
|
|
37
|
+
(...arguments_: Parameters<Function_>) =>
|
|
38
|
+
Promise<Awaited<ReturnType<Function_>>>;
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## ✅ Correct
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import type {Asyncify} from "type-fest";
|
|
45
|
+
|
|
46
|
+
type AsyncVersion<Function_ extends (...arguments_: any[]) => any> =
|
|
47
|
+
Asyncify<Function_>;
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Behavior and migration notes
|
|
51
|
+
|
|
52
|
+
- This rule intentionally overlaps with `SetReturnType` only for the exact asyncified return shape, and it takes precedence there.
|
|
53
|
+
- It reports both the raw wrapper and the `SetReturnType<..., Promise<Awaited<ReturnType<...>>>>` composition.
|
|
54
|
+
- It ignores non-async `SetReturnType` usage.
|
|
55
|
+
|
|
56
|
+
## ESLint flat config example
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import typefest from "eslint-plugin-typefest";
|
|
60
|
+
|
|
61
|
+
export default [typefest.configs.experimental];
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## When not to use it
|
|
65
|
+
|
|
66
|
+
Disable this rule if your team prefers the explicit wrapper signature or if you want to reserve `Asyncify` for only a subset of wrapper types.
|
|
67
|
+
|
|
68
|
+
## Package documentation
|
|
69
|
+
|
|
70
|
+
TypeFest package documentation:
|
|
71
|
+
|
|
72
|
+
Source file: [`source/asyncify.d.ts`](https://github.com/sindresorhus/type-fest/blob/main/source/asyncify.d.ts)
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import type {Asyncify} from "type-fest";
|
|
76
|
+
|
|
77
|
+
type AsyncVersion<Function_ extends (...arguments_: any[]) => any> =
|
|
78
|
+
Asyncify<Function_>;
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
> **Rule catalog ID:** R093
|
|
82
|
+
|
|
83
|
+
## Further reading
|
|
84
|
+
|
|
85
|
+
- [`type-fest` README](https://github.com/sindresorhus/type-fest)
|
|
86
|
+
- [TypeScript Handbook: Awaited](https://www.typescriptlang.org/docs/handbook/utility-types.html#awaitedtype)
|
|
87
|
+
- [TypeScript Handbook: ReturnType](https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype)
|
|
88
|
+
|
|
89
|
+
## Adoption resources
|
|
90
|
+
|
|
91
|
+
- [Rule adoption checklist](./guides/adoption-checklist.md)
|
|
92
|
+
- [Rollout and fix safety](./guides/rollout-and-fix-safety.md)
|
|
93
|
+
- [Preset selection strategy](./guides/preset-selection-strategy.md)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# prefer-type-fest-conditional-except
|
|
2
|
+
|
|
3
|
+
Prefer [`ConditionalExcept`](https://github.com/sindresorhus/type-fest/blob/main/source/conditional-except.d.ts) from `type-fest` over `Except<Base, ConditionalKeys<Base, Condition>>` compositions.
|
|
4
|
+
|
|
5
|
+
This rule lives only in the experimental preset and reports without autofixing.
|
|
6
|
+
|
|
7
|
+
## Targeted pattern scope
|
|
8
|
+
|
|
9
|
+
This rule focuses on direct `type-fest` compositions that already use both `Except` and `ConditionalKeys` together.
|
|
10
|
+
|
|
11
|
+
- `Except<Base, ConditionalKeys<Base, Condition>>`
|
|
12
|
+
- the same shape when `Except` and `ConditionalKeys` are imported under local aliases from `type-fest`
|
|
13
|
+
|
|
14
|
+
It intentionally skips builtin `Omit<Base, ConditionalKeys<Base, Condition>>` shapes to avoid overlapping with the stable `prefer-type-fest-except` rule.
|
|
15
|
+
|
|
16
|
+
## What this rule reports
|
|
17
|
+
|
|
18
|
+
This rule reports `type-fest` compositions when all of the following are true:
|
|
19
|
+
|
|
20
|
+
- the outer type reference resolves to `Except`
|
|
21
|
+
- the second type argument resolves to `ConditionalKeys`
|
|
22
|
+
- the base type passed to `Except` matches the base type passed to `ConditionalKeys`
|
|
23
|
+
|
|
24
|
+
The rule is currently **report-only**. It does not autofix or suggest a replacement yet.
|
|
25
|
+
|
|
26
|
+
## Why this rule exists
|
|
27
|
+
|
|
28
|
+
`ConditionalExcept<Base, Condition>` expresses the intent of conditional omission directly.
|
|
29
|
+
|
|
30
|
+
- Readers do not need to mentally expand two helper types to understand the result.
|
|
31
|
+
- The single helper form is shorter and easier to scan in large type aliases.
|
|
32
|
+
- The intent stays aligned with the upstream Type-Fest utility that already models this exact composition.
|
|
33
|
+
|
|
34
|
+
## ❌ Incorrect
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import type {ConditionalKeys, Except} from "type-fest";
|
|
38
|
+
|
|
39
|
+
type Example = {
|
|
40
|
+
count: number;
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
name: string;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
type NonStrings = Except<Example, ConditionalKeys<Example, string>>;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## ✅ Correct
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import type {ConditionalExcept} from "type-fest";
|
|
52
|
+
|
|
53
|
+
type Example = {
|
|
54
|
+
count: number;
|
|
55
|
+
enabled: boolean;
|
|
56
|
+
name: string;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
type NonStrings = ConditionalExcept<Example, string>;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Behavior and migration notes
|
|
63
|
+
|
|
64
|
+
- This rule only reports the direct `Except<..., ConditionalKeys<...>>` composition.
|
|
65
|
+
- It ignores builtin `Omit` forms on purpose to avoid duplicate reporting with `prefer-type-fest-except`.
|
|
66
|
+
- It ignores compositions where the `ConditionalKeys` base type does not exactly match the `Except` base type.
|
|
67
|
+
|
|
68
|
+
## Additional examples
|
|
69
|
+
|
|
70
|
+
### ❌ Incorrect — Additional example
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import type {ConditionalKeys as MatchingKeys, Except as StrictExcept} from "type-fest";
|
|
74
|
+
|
|
75
|
+
type Example = {
|
|
76
|
+
count: number;
|
|
77
|
+
enabled: boolean;
|
|
78
|
+
name: string;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
type NonStrings = StrictExcept<Example, MatchingKeys<Example, string>>;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### ✅ Correct — Additional example
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import type {ConditionalExcept} from "type-fest";
|
|
88
|
+
|
|
89
|
+
type Example = {
|
|
90
|
+
count: number;
|
|
91
|
+
enabled: boolean;
|
|
92
|
+
name: string;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
type NonStrings = ConditionalExcept<Example, string>;
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## ESLint flat config example
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import typefest from "eslint-plugin-typefest";
|
|
102
|
+
|
|
103
|
+
export default [typefest.configs.experimental];
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## When not to use it
|
|
107
|
+
|
|
108
|
+
Disable this rule if your team prefers explicit helper-type composition over the shorter canonical alias, or if you want `Except` and `ConditionalKeys` to stay visible for teaching purposes.
|
|
109
|
+
|
|
110
|
+
## Package documentation
|
|
111
|
+
|
|
112
|
+
TypeFest package documentation:
|
|
113
|
+
|
|
114
|
+
Source file: [`source/conditional-except.d.ts`](https://github.com/sindresorhus/type-fest/blob/main/source/conditional-except.d.ts)
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import type {ConditionalExcept} from "type-fest";
|
|
118
|
+
|
|
119
|
+
type Example = {
|
|
120
|
+
a: string;
|
|
121
|
+
b: string | number;
|
|
122
|
+
c: () => void;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
type NonStringKeysOnly = ConditionalExcept<Example, string>;
|
|
126
|
+
//=> {b: string | number; c: () => void}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
> **Rule catalog ID:** R087
|
|
130
|
+
|
|
131
|
+
## Further reading
|
|
132
|
+
|
|
133
|
+
- [`type-fest` README](https://github.com/sindresorhus/type-fest)
|
|
134
|
+
- [`type-fest` package reference](https://www.npmjs.com/package/type-fest)
|
|
135
|
+
- [TypeScript Handbook: Conditional Types](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html)
|
|
136
|
+
|
|
137
|
+
## Adoption resources
|
|
138
|
+
|
|
139
|
+
- [Rule adoption checklist](./guides/adoption-checklist.md)
|
|
140
|
+
- [Rollout and fix safety](./guides/rollout-and-fix-safety.md)
|
|
141
|
+
- [Preset selection strategy](./guides/preset-selection-strategy.md)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# prefer-type-fest-conditional-keys
|
|
2
|
+
|
|
3
|
+
Prefer [`ConditionalKeys`](https://github.com/sindresorhus/type-fest/blob/main/source/conditional-keys.d.ts) from `type-fest` over manual `keyof`-remapped key filters.
|
|
4
|
+
|
|
5
|
+
This rule lives only in the experimental preset and reports without autofixing.
|
|
6
|
+
|
|
7
|
+
## Targeted pattern scope
|
|
8
|
+
|
|
9
|
+
This rule focuses on the common pattern that filters keys by value condition through `keyof` over a mapped type:
|
|
10
|
+
|
|
11
|
+
- `keyof { [K in keyof Base as Base[K] extends Condition ? K : never]: ... }`
|
|
12
|
+
|
|
13
|
+
It intentionally skips more elaborate helpers that involve strictness wrappers, tuple-to-object conversions, or additional conditional layers.
|
|
14
|
+
|
|
15
|
+
## What this rule reports
|
|
16
|
+
|
|
17
|
+
This rule reports `keyof`-wrapped mapped types when all of the following are true:
|
|
18
|
+
|
|
19
|
+
- the key constraint is `keyof Base`
|
|
20
|
+
- the key remap condition is `Base[K] extends Condition ? K : never`
|
|
21
|
+
- the outer type operator is `keyof`
|
|
22
|
+
|
|
23
|
+
The rule is currently **report-only**. It does not autofix or suggest a replacement yet.
|
|
24
|
+
|
|
25
|
+
## Why this rule exists
|
|
26
|
+
|
|
27
|
+
`ConditionalKeys<Base, Condition>` is easier to read than the raw remapping recipe.
|
|
28
|
+
|
|
29
|
+
- The helper name explains the intent immediately.
|
|
30
|
+
- Readers do not need to mentally evaluate the mapped type and outer `keyof`.
|
|
31
|
+
- Standardizing on Type-Fest reduces duplicated local helper patterns.
|
|
32
|
+
|
|
33
|
+
## ❌ Incorrect
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
type KeysMatching<Base, Condition> = keyof {
|
|
37
|
+
[Key in keyof Base as Base[Key] extends Condition
|
|
38
|
+
? Key
|
|
39
|
+
: never]: never;
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## ✅ Correct
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import type {ConditionalKeys} from "type-fest";
|
|
47
|
+
|
|
48
|
+
type KeysMatching<Base, Condition> = ConditionalKeys<Base, Condition>;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Behavior and migration notes
|
|
52
|
+
|
|
53
|
+
- This rule targets only the narrow `keyof`-remapped key-filter pattern.
|
|
54
|
+
- It ignores plain mapped types that are not wrapped in `keyof`.
|
|
55
|
+
- It also ignores more elaborate Type-Fest-internal strictness variants to avoid speculative reporting.
|
|
56
|
+
|
|
57
|
+
## ESLint flat config example
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import typefest from "eslint-plugin-typefest";
|
|
61
|
+
|
|
62
|
+
export default [typefest.configs.experimental];
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## When not to use it
|
|
66
|
+
|
|
67
|
+
Disable this rule if your project prefers the explicit remapped-key form or if your helper intentionally diverges from Type-Fest semantics.
|
|
68
|
+
|
|
69
|
+
## Package documentation
|
|
70
|
+
|
|
71
|
+
TypeFest package documentation:
|
|
72
|
+
|
|
73
|
+
Source file: [`source/conditional-keys.d.ts`](https://github.com/sindresorhus/type-fest/blob/main/source/conditional-keys.d.ts)
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import type {ConditionalKeys} from "type-fest";
|
|
77
|
+
|
|
78
|
+
type KeysMatching<Base, Condition> = ConditionalKeys<Base, Condition>;
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
> **Rule catalog ID:** R095
|
|
82
|
+
|
|
83
|
+
## Further reading
|
|
84
|
+
|
|
85
|
+
- [`type-fest` README](https://github.com/sindresorhus/type-fest)
|
|
86
|
+
- [TypeScript Handbook: Mapped Types](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html)
|
|
87
|
+
- [TypeScript Handbook: Conditional Types](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html)
|
|
88
|
+
|
|
89
|
+
## Adoption resources
|
|
90
|
+
|
|
91
|
+
- [Rule adoption checklist](./guides/adoption-checklist.md)
|
|
92
|
+
- [Rollout and fix safety](./guides/rollout-and-fix-safety.md)
|
|
93
|
+
- [Preset selection strategy](./guides/preset-selection-strategy.md)
|