/
prefer-reduce-type-parameter.ts
112 lines (99 loc) · 2.83 KB
/
prefer-reduce-type-parameter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import {
AST_NODE_TYPES,
TSESTree,
} from '@typescript-eslint/experimental-utils';
import * as util from '../util';
type MemberExpressionWithCallExpressionParent = TSESTree.MemberExpression & {
parent: TSESTree.CallExpression;
};
const getMemberExpressionName = (
member: TSESTree.MemberExpression,
): string | null => {
if (!member.computed) {
return member.property.name;
}
if (
member.property.type === AST_NODE_TYPES.Literal &&
typeof member.property.value === 'string'
) {
return member.property.value;
}
return null;
};
export default util.createRule({
name: 'prefer-reduce-type-parameter',
meta: {
type: 'problem',
docs: {
category: 'Best Practices',
recommended: false,
description:
'Prefer using type parameter when calling `Array#reduce` instead of casting',
requiresTypeChecking: true,
},
messages: {
preferTypeParameter:
'Unnecessary cast: Array#reduce accepts a type parameter for the default value.',
},
fixable: 'code',
schema: [],
},
defaultOptions: [],
create(context) {
const service = util.getParserServices(context);
const checker = service.program.getTypeChecker();
return {
'CallExpression > MemberExpression.callee'(
callee: MemberExpressionWithCallExpressionParent,
): void {
if (getMemberExpressionName(callee) !== 'reduce') {
return;
}
const [, secondArg] = callee.parent.arguments;
if (
callee.parent.arguments.length < 2 ||
!util.isTypeAssertion(secondArg)
) {
return;
}
// Get the symbol of the `reduce` method.
const tsNode = service.esTreeNodeToTSNodeMap.get(callee.object);
const calleeObjType = util.getConstrainedTypeAtLocation(
checker,
tsNode,
);
// Check the owner type of the `reduce` method.
if (checker.isArrayType(calleeObjType)) {
context.report({
messageId: 'preferTypeParameter',
node: secondArg,
fix: fixer => {
const fixes = [
fixer.removeRange([
secondArg.range[0],
secondArg.expression.range[0],
]),
fixer.removeRange([
secondArg.expression.range[1],
secondArg.range[1],
]),
];
if (!callee.parent.typeParameters) {
fixes.push(
fixer.insertTextAfter(
callee,
`<${context
.getSourceCode()
.getText(secondArg.typeAnnotation)}>`,
),
);
}
return fixes;
},
});
return;
}
},
};
},
});