// Bad
if (isSomeState1) {
anyAction1()
} else if (isSomeState2) {
anuAction2()
} else {
req = {...}
if (!loading) {
anyRequest(req)
}
}
// Good
// return 을 사용함으로써, 대부분의 경우에서 else 와 else if 문을 피할 수 있습니다.
if (isSomeState1) {
anyAction1()
return;
}
if (isSomeState2) {
anyAction2()
return;
}
if (loading) return;
const req = {...}
anyRequest(req)
예외케이스를 우선적으로 리턴해주세요
// Bad
if(isShow) {
handleScroll();
document.addEventListener('scroll', handleScroll);
if(outerRef.current) {
if(window.scrollY < outerRef.current.offsetTop) {
setImageY(IMAGE_SHOW);
setBoxTransFormY([BOX_DOWN, BOX_DOWN, BOX_DOWN, BOX_DOWN]);
}
}
// Good
// 예외 상황일때 우선적으로 return 해줌으로써, 코드에 대한 파악이 더욱 쉬워집니다.
if (!isShow) return;
handleScroll();
document.addEventListener('scroll', handleScroll)
if (!outerRef.current) return;
if (window.scrollY >= outerRef.current.offsetTop) return;
setImageY(IMAGE_SHOW);
setBoxTransFormY([BOX_DOWN, BOX_DOWN, BOX_DOWN, BOX_DOWN]);
함수에서 권장되는 규칙입니다.
하나의 함수는 한가지 일만 하게 해주세요
// Bad
function sendEmailToClient(clients: Client[]) {
clients.forEach((client) => {
const clientRecord = database.lookup(client);
if (clientRecord.isActive()) {
email(client);
}
});
}
// Good
function sendEmailToClient(clients: Client[]) {
clients.filter(isActiveClient).forEach(email);
}
function isActiveClient(client: Client) {
const clientRecord = database.lookup(client);
return clientRecord.isActive();
}
되도록 순수함수로 작성해주세요
//Bad
let name = 'Robert C. Martin'; // 아래의 함수에서 참조하는 전역 변수입니다.
function convertToBase64() {
name = btoa(name);
}
convertToBase64(); // 이 이름을 사용하는 다른 함수가 있다면, 그것은 Base64 값을 반환할 것입니다
console.log(name); // 'Robert C. Martin'이 출력되는 것을 예상했지만 'Um9iZXJ0IEMuIE1hcnRpbg=='가 출력됨
// Good
const name = 'Robert C. Martin';
function convertToBase64(text: string): string {
return btoa(text);
}
const encodedName = convertToBase64(name);
console.log(name);\
함수의 매개변수는 2개 이하로 작성해주세요. 많아진다면 하나의 객체로 넘겨줄 수 있습니다.
커스텀 타입정의는 해당 query 나 mutation 이 받는 함수의 타입을 기반으로, param 과 onSuccess 와 같은 option 에 대한 타입정의를 생성해 줍니다.
import { UseQueryParams } from '@/types/module/react-query/use-query-params';
// custom type 을 사용해서 선언하기
export function useGetExampleListQuery(
params: UseQueryParams<typeof exampleApi.getList>,
) { ... }
// 사용 시
const { data } = useGetExmplaeListQuery({
variables: { offset: 0, limit: 10 } // 넘겨준 함수의 parameter 로 타입정의가 되어 type-chcking 이 가능해집니다.
options: {
onSuccess: (res) => {
res.title // 넘겨준 함수의 return type 으로 타입 정의가 되어서, type-checking 이 가능해집니다.
}
}
})
import { UseMutationParams } from '@/types/module/react-query/use-mutation-params';
// custom type 을 사용해서 선언하기
export function useCreateExampleMutation(
params?: UseMutationParams<typeof exampleApi.create>,
) { ... }
// 사용 시
const { mutate } = useCreateExampleMutation({
options: {
onSuccess: (res) => {
res.title // 넘겨준 함수의 return type 으로 타입 정의가 되어서, type-checking 이 가능해집니다.
}
}
})
mutate({ title: "내 제목" }) // 넘겨준 함수의 parameter 로 타입정의가 되어 type-chcking 이 가능해집니다.
class 의 method 의 parameter 는 반드시 1개 이하로 작성하기
export class ExampleApi {
// bad : 커스텀 타입인 UseQueryParams 이 제대로 작동하지 않을 수 있습니다.
getList = async (offset: number, limit: number) => {...};
// good
getList = async (params: {offset: number, limit: number}) => {...};
}
전역적으로 사용하는 util 은 test 코드를 포함하기
전역적으로 사용하는 함수의 경우엔 재 사용성이 높고, 타인이 사용할 가능성이 높기 때문에 검증이 필수적입니다.
테스트 코드를 통해 브라우저를 실행하지 않고도 검증을 확인 할 수 있으며, 결과값을 알 수 있기 때문에 문서화 효과를 누릴 수 있습니다.
import { formatNumberKR } from '../format-number-kr';
describe('formatNumberKR', () => {
it('should format number to Korean locale string', () => {
expect(formatNumberKR(1000000)).toBe('1,000,000');
expect(formatNumberKR(123456789)).toBe('123,456,789');
expect(formatNumberKR(1234.567)).toBe('1,234.567');
expect(formatNumberKR(-987654321)).toBe('-987,654,321');
expect(formatNumberKR(0)).toBe('0');
// 주의 : 소수점4째 자리 부터는 반올림 처리 됩니다.
expect(formatNumberKR(1234.5674)).toBe('1,234.567');
expect(formatNumberKR(1234.5676)).toBe('1,234.568');
});
});
전역적으로 사용하는 Utility(Generic) 타입은 예시코드를 사용하기
전역적으로 사용하는 utility 타입의 경우엔 타인이 사용할 가능성이 높기 때문에, 미리 결과를 알 수 있는 예시코드를 포함해 줍니다.
// type Example = ItemOf<['a', 'b', 'c']>;
// Example = "a" | "b" | "c"
export type ItemOf<T extends Array<any> | readonly any[]> = T[number];
Reference
클린 코드에 관심이 많으신가요?
저희의 코드 컨벤션은 여러 문서 중, 아래 두 문서를 주로 참고하여 작성되었습니다.
Comment_
타입스크립트는 자바스크립트의 Super Set 이듯이,
위의 게시물도 우리 클린코드의 Super Set 입니다.
꼭 확인해 보세요!
Comment_
똑개 코드원칙에서 소개된 추상화, 단일책임, 응집도에 대해 친절하고 자세히 설명되어있는 영상입니다
길지 않으니 꼭 시청해 주세요
Reference: TokTokHan
Comment_
똑개에서 추려본 리액트 공식문서의 핵심글들을 위 게시물에서 확인해보세요!
Comment_
타입스크립트의 다양한 사용방법을 확인해 보고, 코드를 더욱 안전하게 작성해보세요
Comment_
테스트 코드를 우리 개발 환경에서 빠르게 시작하고 싶다면 위 게시물을 확인해 보세요
컨벤션 문서가 조금 어렵게 느껴지신다면
Basic 가이드의 다른 탭을 확인해보세요.
Apis, Type 주제별로 조금 더 상세한 설명과 함께 작성되어있습니다.
보일러 탬플릿엔 어떤 기능들이 있나요?
Boiler Template 게시물을 확인해보세요.
미리 구현된 기능들을 사용하며, 개발해보세요
Naming: Special Case
Code Style: Naming
Code Style: Object
Code Style: If Statement
Code Style: Function
Code Style: Component
Code Style: Apis
서버와 통신하는 api 를 선언 할시 지켜야할 규칙입니다. 더 상세한 설명은 에서 확인 할 수 있습니다.