Skip to content

Commit c0c33f4

Browse files
TypeScript usage - configuration & code adaptation (#25)
* Add and configure TypeScript for RN project * Add TypeScript types check to CI workflow The CI will now check the TypeScript code against any errors. All files containing JavaScript code has been renamed to indictate TypeScript (*.tsx). * Fix: tsc --pretty errors and type errors * Cover review remarks
1 parent 9aa8062 commit c0c33f4

File tree

11 files changed

+211
-69
lines changed

11 files changed

+211
-69
lines changed

.circleci/config.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ jobs:
4343
- run:
4444
name: "Verify the standards and code quality"
4545
command: npx eslint ./src/**
46+
- run:
47+
name: "Check the TypeScript code quality"
48+
command: yarn tsc --pretty
4649

4750
# Application build
4851
build-Application-Configuration-Platform:

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,17 @@
2121
"@babel/runtime": "^7.8.4",
2222
"@callstack/eslint-config": "^11.0.0",
2323
"@react-native-community/eslint-config": "^1.1.0",
24+
"@types/jest": "^26.0.23",
25+
"@types/react": "^17.0.13",
26+
"@types/react-native": "^0.64.10",
27+
"@types/react-test-renderer": "^17.0.1",
2428
"babel-jest": "^25.1.0",
2529
"eslint": "^7.29.0",
2630
"jest": "^25.1.0",
2731
"metro-react-native-babel-preset": "^0.59.0",
2832
"prettier": "2.3.2",
29-
"react-test-renderer": "16.13.1"
33+
"react-test-renderer": "16.13.1",
34+
"typescript": "^4.3.5"
3035
},
3136
"husky": {
3237
"hooks": {

src/CreateNotePanel.js renamed to src/CreateNotePanel.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,27 @@ import {
1414
} from 'react-native';
1515
import Colors from './Resources/Colors';
1616

17-
class CreateNotePanel extends React.Component {
18-
constructor(props) {
17+
interface Props {}
18+
19+
interface State {
20+
title: string;
21+
message: string;
22+
}
23+
24+
class CreateNotePanel extends React.Component<Props, State> {
25+
constructor(props: Props) {
1926
super(props);
2027
this.state = {
2128
title: '',
2229
message: '',
2330
};
2431
}
2532

26-
titleOnChange = (text) => {
33+
titleOnChange = (text: string) => {
2734
this.setState({title: text});
2835
};
2936

30-
messageOnChange = (text) => {
37+
messageOnChange = (text: string) => {
3138
this.setState({message: text});
3239
};
3340

src/NoteWidgetDetailsPanel.js renamed to src/NoteWidgetDetailsPanel.tsx

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,17 @@ import {
1414
} from 'react-native';
1515
import Colors from './Resources/Colors';
1616

17-
class NoteWidgetDetailsPanel extends React.Component {
18-
constructor(props) {
17+
interface Props {}
18+
19+
interface State {
20+
id: number;
21+
title: string;
22+
message: string;
23+
isEditing: boolean;
24+
}
25+
26+
class NoteWidgetDetailsPanel extends React.Component<Props, State> {
27+
constructor(props: Props) {
1928
super(props);
2029
this.state = {
2130
id: 0,
@@ -27,41 +36,44 @@ class NoteWidgetDetailsPanel extends React.Component {
2736

2837
async componentDidMount() {
2938
await NativeModules.NoteWidgetClickHandler.openedNoteID()
30-
.then((result) => {
39+
.then((result: number) => {
3140
this.setState({id: result});
3241
this.getNoteTitle();
3342
this.getNoteMessage();
3443
return 0;
3544
})
36-
.catch((error) => {
37-
Alert.alert('ERROR!', `Could not find the opened note\n${error}`);
45+
.catch((error: Error) => {
46+
Alert.alert(
47+
'ERROR!',
48+
`Could not find the opened note\n${error.message}`,
49+
);
3850
});
3951
}
4052

41-
titleOnChange = (text) => {
53+
titleOnChange = (text: string) => {
4254
this.setState({title: text});
4355
};
4456

45-
messageOnChange = (text) => {
57+
messageOnChange = (text: string) => {
4658
this.setState({message: text});
4759
};
4860

4961
getNoteTitle = async () => {
5062
await NativeModules.Database.getNoteTitle(this.state.id)
51-
.then((result) => {
63+
.then((result: string) => {
5264
this.setState({title: result});
5365
return 0;
5466
})
55-
.catch((error) => Alert.alert('ERROR!', `${error}`));
67+
.catch((error: Error) => Alert.alert('ERROR!', `${error.message}`));
5668
};
5769

5870
getNoteMessage = async () => {
5971
await NativeModules.Database.getNotePost(this.state.id)
60-
.then((result) => {
72+
.then((result: string) => {
6173
this.setState({message: result});
6274
return 0;
6375
})
64-
.catch((error) => Alert.alert('ERROR!', `${error}`));
76+
.catch((error: Error) => Alert.alert('ERROR!', `${error.message}`));
6577
};
6678

6779
cancelButtonPressed = () => {

src/NotesMainPanel.js renamed to src/NotesMainPanel.tsx

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,37 @@ import {
1616
import NoteWidget from './Widgets/NoteWidget';
1717
import Colors from './Resources/Colors';
1818

19-
const window = Dimensions.get('window');
20-
const screen = Dimensions.get('screen');
21-
2219
const noteWidgetWidth = 300;
2320

24-
class NotesMainPanel extends React.Component {
25-
constructor(props) {
21+
function calculateColumnWidth() {
22+
return Math.floor(Dimensions.get('window').width / noteWidgetWidth);
23+
}
24+
25+
interface Props {}
26+
27+
interface INote {
28+
key: number;
29+
title: string;
30+
shortMessage: string;
31+
}
32+
33+
interface State {
34+
notes: Array<INote>;
35+
columns: number;
36+
}
37+
38+
class NotesMainPanel extends React.Component<Props, State> {
39+
constructor(props: Props) {
2640
super(props);
2741
this.state = {
2842
notes: [],
29-
dimensions: {window, screen},
30-
columns: this.calculateColumnWidth(window),
31-
isMounted: false,
43+
columns: calculateColumnWidth(),
3244
};
3345
}
3446

35-
calculateColumnWidth = () => {
36-
return Math.floor(Dimensions.get('window').width / noteWidgetWidth);
37-
};
38-
39-
onChange = ({window, screen}) => {
47+
onChange = () => {
4048
this.setState({
41-
dimensions: {window, screen},
42-
columns: this.calculateColumnWidth(),
49+
columns: calculateColumnWidth(),
4350
});
4451
};
4552

@@ -52,25 +59,16 @@ class NotesMainPanel extends React.Component {
5259
Dimensions.removeEventListener('change', this.onChange);
5360
}
5461

55-
createNotesKeys = async (notesIDs) => {
62+
createNotesKeys = async (notesIDs: Array<INote>) => {
5663
this.setState({notes: notesIDs});
5764
};
5865

5966
getDataFromDatabase = async () => {
6067
await NativeModules.Database.getAllNotesIDs()
61-
.then((result) => this.createNotesKeys(result))
62-
.catch((error) => Alert.alert('ERROR!', `Result: ${error}`));
63-
};
64-
65-
renderNote = (notes) => {
66-
return (
67-
<NoteWidget
68-
width={noteWidgetWidth}
69-
ID={notes.item.key}
70-
title={notes.item.title}
71-
shortMessage={notes.item.shortMessage}
72-
/>
73-
);
68+
.then((result: Array<INote>) => this.createNotesKeys(result))
69+
.catch((error: Error) =>
70+
Alert.alert('ERROR!', `Result: ${error.message}`),
71+
);
7472
};
7573

7674
renderWelcomePage = () => {
@@ -89,11 +87,18 @@ class NotesMainPanel extends React.Component {
8987
renderNotesPage = () => {
9088
return (
9189
<View style={styles.mainContainer}>
92-
<FlatList
90+
<FlatList<INote>
9391
key={this.state.columns}
9492
numColumns={this.state.columns}
9593
data={this.state.notes}
96-
renderItem={this.renderNote}
94+
renderItem={({item}) => (
95+
<NoteWidget
96+
width={noteWidgetWidth}
97+
id={item.key}
98+
title={item.title}
99+
shortMessage={item.shortMessage}
100+
/>
101+
)}
97102
/>
98103
</View>
99104
);
File renamed without changes.

src/ToDoListPanel.js renamed to src/ToDoListPanel.tsx

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,38 @@ import DateTimePicker from '@react-native-community/datetimepicker';
1515
import TaskWidget from './Widgets/TaskWidget';
1616
import Colors from './Resources/Colors';
1717

18-
class ToDoListPanel extends React.Component {
19-
constructor(props) {
18+
interface Props {}
19+
20+
interface Task {
21+
key: number;
22+
message: string;
23+
dueDate: Date | undefined;
24+
}
25+
26+
interface State {
27+
tasks: Array<Task>;
28+
number: number;
29+
message: string;
30+
selectedDate: Date | undefined;
31+
}
32+
33+
class ToDoListPanel extends React.Component<Props, State> {
34+
constructor(props: Props) {
2035
super(props);
2136
this.state = {
2237
tasks: [],
2338
number: 0,
2439
message: '',
25-
selectedDate: new Date(0),
40+
selectedDate: new Date(),
2641
};
2742
}
2843

29-
onChange = (event, selectedDate) => {
44+
onChange = (event: Event, selectedDate?: Date) => {
3045
const currentDate = selectedDate;
3146
this.setState({selectedDate: currentDate});
3247
};
3348

34-
messageOnChange = (text) => {
49+
messageOnChange = (text: string) => {
3550
this.setState({message: text});
3651
};
3752

@@ -52,24 +67,20 @@ class ToDoListPanel extends React.Component {
5267
});
5368
};
5469

55-
renderTask = (tasks) => {
56-
return (
57-
<TaskWidget
58-
ID={tasks.item.key}
59-
message={tasks.item.message}
60-
dueDate={tasks.item.dueDate}
61-
/>
62-
);
63-
};
64-
6570
render() {
6671
return (
6772
<View style={styles.mainPanel}>
6873
<View style={styles.flatListPanel}>
6974
<FlatList
7075
numColumns={1}
7176
data={this.state.tasks}
72-
renderItem={this.renderTask}
77+
renderItem={({item}) => (
78+
<TaskWidget
79+
id={item.key}
80+
message={item.message}
81+
dueDate={item.dueDate}
82+
/>
83+
)}
7384
/>
7485
</View>
7586

@@ -83,7 +94,7 @@ class ToDoListPanel extends React.Component {
8394
<View style={styles.createButtons}>
8495
<Button title={'Add'} onPress={this.addButtonPressed} />
8596
<DateTimePicker
86-
value={this.state.selectedDate}
97+
value={this.state.selectedDate || new Date()}
8798
is24Hour={true}
8899
display="default"
89100
onChange={this.onChange}

src/Widgets/NoteWidget.js renamed to src/Widgets/NoteWidget.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,18 @@ import {
1313
} from 'react-native';
1414
import Colors from '../Resources/Colors';
1515

16-
export default function NoteWidget(props) {
17-
const {width, ID, title, shortMessage} = props;
16+
interface Props {
17+
width: number;
18+
id: number;
19+
title: string;
20+
shortMessage: string;
21+
}
22+
23+
export default function NoteWidget(props: Props) {
24+
const {width, id, title, shortMessage} = props;
1825

1926
const enterNote = () => {
20-
NativeModules.NoteWidgetClickHandler.openWidget(ID);
27+
NativeModules.NoteWidgetClickHandler.openWidget(id);
2128
};
2229

2330
return (

src/Widgets/TaskWidget.js renamed to src/Widgets/TaskWidget.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ import {AppRegistry, StyleSheet, Text, View} from 'react-native';
88
import CheckBox from '@react-native-community/checkbox';
99
import Colors from '../Resources/Colors';
1010

11-
export default function TaskWidget(props) {
11+
interface Props {
12+
id: number;
13+
message: string;
14+
dueDate: Date | undefined;
15+
}
16+
17+
export default function TaskWidget(props: Props) {
1218
const {message, dueDate} = props;
1319

1420
const [isDone, setIsDone] = useState(false);

tsconfig.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"compilerOptions": {
3+
"allowJs": true,
4+
"allowSyntheticDefaultImports": true,
5+
"esModuleInterop": true,
6+
"isolatedModules": true,
7+
"jsx": "react",
8+
"lib": ["es6"],
9+
"moduleResolution": "node",
10+
"noEmit": true,
11+
"strict": true,
12+
"target": "esnext"
13+
},
14+
"exclude": [
15+
"node_modules",
16+
"babel.config.js",
17+
"metro.config.js",
18+
"jest.config.js"
19+
]
20+
}

0 commit comments

Comments
 (0)