This is a non-exhaustive list of the coding patterns the WorkWave RouteManager's front-end team follows. The patterns are based on years of experience writing, debugging, and refactoring front-end applications with React and TypeScript but evolves constantly. Most of the possible improvements and the code smells are detected during the code reviews and the pair programming sessions.
(please note: I do not work for WorkWave anymore, these patterns will not be updated)
(last update: 2022, March)
We guarantee objects' immutability through ESLint. We use the no-param-reassign rule with the following configuration
'no-param-reassign': [
'error',
{
props: true,
ignorePropertyModificationsForRegex: [
// standard array.reduce
'acc',
// array.reduce with params named differently from `acc`. They must end with `Acc` at least
'Acc$',
// standard Immer draft
'draft',
// Immer drafts
'Draft$',
// refs passed around hooks
'Ref$',
// parameters prefixed by `mutable`
'^mutable',
],
},
],
Please note that enabling mutability through variable names helps the reader only if the whole chain of callers uses the prefix/suffix.
// ❌ don't
function a(array: string[]) {
b(array)
}
function b(array: string[]) {
c(array)
}
function c(mutableArray: string[]) {
mutableArray.splice(1)
}
// ✅ do
function a(mutableArray: string[]) {
b(mutableArray)
}
function b(mutableArray: string[]) {
c(mutableArray)
}
function c(mutableArray: string[]) {
mutableArray.splice(1)
}
Accumulators
Array.reduce
accumulators can be mutated, if named acc
or suffixed by Acc
.
// ❌ don't
[1, 2, 3].reduce<number>((map, item) => {
return map[item] = item
}, 0)
// ✅ do
[1, 2, 3].reduce<number>((acc, item) => {
return acc[item] = item
}, 0)
[1, 2, 3].reduce<number>((mapAcc, item) => {
return mapAcc[item] = item
}, 0)
Immer' drafts
Immer' drafts can be mutated, if named draft
or suffixed by draft
.
// ❌ don't
const next = produce(prev, temp => {
temp.message = message
})
// ✅ do
const next = produce(prev, draft => {
draft.message = message
})
const next = produce(prev, emailDraft => {
emailDraft.message = message
})
React's refs
React's refs can be mutated, if suffixed by Ref
.
// ❌ don't
export function useNow(now) {
useEffect(() => {
now.current = Date.now()
}, [])
}
export function useNow(ref) {
useEffect(() => {
ref.current = Date.now()
}, [])
}
// ✅ do
export function useNow(nowRef) {
useEffect(() => {
nowRef.current = Date.now()
}, [])
}
Mutable arguments
The arguments of a function can be mutated, if prefixed by mutable
.
// ❌ don't
export function setToday(dates) {
dates.today = new Date()
}
// ✅ do
export function setToday(mutableDates) {
mutableDates.today = new Date()
}
Top comments (0)