* fixing links for i18n ease * fixing links for i18n ease * revert brain fart * hopefully now the link works * changing links for ease of translation
3.7 KiB
Codebase Best Practices
General JavaScript
In most cases, our linter will warn of any formatting which goes against this codebase's preferred practice.
It is encouraged to use functional components over class-based components.
Specific TypeScript
Migrating a JavaScript File to TypeScript
Retaining Git File History
Sometimes changing the file from <filename>.js
to <filename>.ts
(or .tsx
) causes the original file to be deleted, and a new one created, and other times the filename just changes - in terms of Git. Ideally, we want the file history to be preserved.
The best bet at achieving this is to:
- Rename the file
- Commit with the flag
--no-verify
to prevent Husky from complaining about the lint errors - Refactor to TypeScript for migration, in a separate commit
Note
Editors like VSCode are still likely to show you the file has been deleted and a new one created. If you use the CLI to
git add .
, then VSCode will show the file as renamed in stage
Naming Conventions
Interfaces and Types
For the most part, it is encouraged to use interface declarations over type declarations.
React Component Props - suffix with Props
interface MyComponentProps {}
// type MyComponentProps = {};
const MyComponent = (props: MyComponentProps) => {};
React Stateful Components - suffix with State
interface MyComponentState {}
// type MyComponentState = {};
class MyComponent extends Component<MyComponentProps, MyComponentState> {}
Default - object name in PascalCase
interface MyObject {}
// type MyObject = {};
const myObject: MyObject = {};
Redux
Action Definitions
enum AppActionTypes = {
actionFunction = 'actionFunction'
}
export const actionFunction = (
arg: Arg
): ReducerPayload<AppActionTypes.actionFunction> => ({
type: AppActionTypes.actionFunction,
payload: arg
});
How to Reduce
// Base reducer action without payload
type ReducerBase<T> = { type: T };
// Logic for handling optional payloads
type ReducerPayload<T extends AppActionTypes> =
T extends AppActionTypes.actionFunction
? ReducerBase<T> & {
payload: AppState['property'];
}
: ReducerBase<T>;
// Switch reducer exported to Redux combineReducers
export const reducer = (
state: AppState = initialState,
action: ReducerPayload<AppActionTypes>
): AppState => {
switch (action.type) {
case AppActionTypes.actionFunction:
return { ...state, property: action.payload };
default:
return state;
}
};
How to Dispatch
Within a component, import the actions and selectors needed.
// Add type definition
interface MyComponentProps {
actionFunction: typeof actionFunction;
}
// Connect to Redux store
const mapDispatchToProps = {
actionFunction
};
// Example React Component connected to store
const MyComponent = ({ actionFunction }: MyComponentProps): JSX.Element => {
const handleClick = () => {
// Dispatch function
actionFunction();
};
return <button onClick={handleClick}>freeCodeCamp is awesome!</button>;
};
export default connect(null, mapDispatchToProps)(MyComponent);