* fixing links for i18n ease * fixing links for i18n ease * revert brain fart * hopefully now the link works * changing links for ease of translation
		
			
				
	
	
		
			136 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			136 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # Codebase Best Practices
 | |
| 
 | |
| ## General JavaScript
 | |
| 
 | |
| In most cases, our [linter](how-to-setup-freecodecamp-locally.md#follow-these-steps-to-get-your-development-environment-ready) 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:
 | |
| 
 | |
| 1. Rename the file
 | |
| 2. Commit with the flag `--no-verify` to prevent Husky from complaining about the lint errors
 | |
| 3. 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`
 | |
| 
 | |
| ```typescript
 | |
| interface MyComponentProps {}
 | |
| // type MyComponentProps = {};
 | |
| const MyComponent = (props: MyComponentProps) => {};
 | |
| ```
 | |
| 
 | |
| React Stateful Components - suffix with `State`
 | |
| 
 | |
| ```typescript
 | |
| interface MyComponentState {}
 | |
| // type MyComponentState = {};
 | |
| class MyComponent extends Component<MyComponentProps, MyComponentState> {}
 | |
| ```
 | |
| 
 | |
| Default - object name in PascalCase
 | |
| 
 | |
| ```typescript
 | |
| interface MyObject {}
 | |
| // type MyObject = {};
 | |
| const myObject: MyObject = {};
 | |
| ```
 | |
| 
 | |
| <!-- #### Redux Actions -->
 | |
| 
 | |
| <!-- TODO: Once refactored to TS, showcase naming convention for Reducers/Actions and how to type dispatch funcs -->
 | |
| 
 | |
| ## Redux
 | |
| 
 | |
| ### Action Definitions
 | |
| 
 | |
| ```typescript
 | |
| enum AppActionTypes = {
 | |
|   actionFunction = 'actionFunction'
 | |
| }
 | |
| 
 | |
| export const actionFunction = (
 | |
|   arg: Arg
 | |
| ): ReducerPayload<AppActionTypes.actionFunction> => ({
 | |
|   type: AppActionTypes.actionFunction,
 | |
|   payload: arg
 | |
| });
 | |
| ```
 | |
| 
 | |
| ### How to Reduce
 | |
| 
 | |
| ```typescript
 | |
| // 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.
 | |
| 
 | |
| ```tsx
 | |
| // 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);
 | |
| ```
 | |
| 
 | |
| <!-- ### Redux Types File -->
 | |
| <!-- The types associated with the Redux store state are located in `client/src/redux/types.ts`... -->
 | |
| 
 | |
| ## Further Literature
 | |
| 
 | |
| - [TypeScript Docs](https://www.typescriptlang.org/docs/)
 | |
| - [TypeScript with React CheatSheet](https://github.com/typescript-cheatsheets/react#readme)
 |