UNPKG

2.5 kBJavaScriptView Raw
1const Components = require('eslint-plugin-react/lib/util/Components');
2
3const {docsUrl, uncast, getName} = require('../utilities');
4
5module.exports = {
6 meta: {
7 docs: {
8 description:
9 'Require that React component state be initialized when it has a non-empty type.',
10 category: 'Possible Errors',
11 recommended: true,
12 uri: docsUrl('react-initialize-state'),
13 },
14 schema: [],
15 },
16
17 create: Components.detect((context, components, utils) => {
18 let classInfo = null;
19
20 return {
21 ClassDeclaration(node) {
22 if (!utils.isES6Component(node)) {
23 return;
24 }
25
26 classInfo = {
27 hasStateType: !classHasEmptyStateType(node),
28 declaredState: false,
29 };
30 },
31 ClassProperty(node) {
32 if (classInfo == null || getName(node.key) !== 'state') {
33 return;
34 }
35
36 if (node.typeAnnotation != null) {
37 classInfo.hasStateType = true;
38 }
39
40 if (node.value == null || node.value.type === 'Literal') {
41 return;
42 }
43
44 classInfo.declaredState = true;
45 },
46 AssignmentExpression(node) {
47 if (classInfo == null) {
48 return;
49 }
50
51 if (
52 node.left.type === 'MemberExpression' &&
53 uncast(node.left.object).type === 'ThisExpression' &&
54 getName(node.left.property) === 'state' &&
55 node.right.type !== 'Literal'
56 ) {
57 classInfo.declaredState = true;
58 }
59 },
60 'ClassDeclaration:exit': (node) => {
61 if (classInfo && classInfo.hasStateType && !classInfo.declaredState) {
62 context.report(
63 node,
64 'You declared a type for state, but did not initialize it.',
65 );
66 }
67
68 classInfo = null;
69 },
70 };
71 }),
72};
73
74function classHasEmptyStateType({superTypeParameters}) {
75 const hasNoStateType =
76 !superTypeParameters ||
77 superTypeParameters.params.length < 2 ||
78 superTypeParameters.params[1].type === 'TSNeverKeyword' ||
79 superTypeParameters.params[1].type === 'TSAnyKeyword' ||
80 superTypeParameters.params[1].type === 'AnyTypeAnnotation';
81
82 if (hasNoStateType) {
83 return true;
84 }
85
86 if (superTypeParameters.params[1].type === 'ObjectTypeAnnotation') {
87 return superTypeParameters.params[1].properties.length === 0;
88 }
89
90 if (superTypeParameters.params[1].type === 'TSTypeLiteral') {
91 return superTypeParameters.params[1].members.length === 0;
92 }
93
94 return false;
95}