Typescript Clean Code

코와->코어·2022년 5월 21일
0

세미나 자료

목록 보기
4/7

Variables
1. 변수 이름은 구체적으로
Bad

// 변수
const AHCageId = 1

// 함수
const isBiggerThan = (a: number, b: number) => {
    return a > b
}

Good

// 변수
const AdmissionHotelCageId = 1

// 함수
const isBiggerThan = (target: number, compareTarget: number) => {
    return a > b
}
  1. 유형이 같다면 동일 명칭으로
    Bad
const getInitAData = () => {}
const generateInitBData = () => {}
const makeInitCData = () => {}

Good

const getInitAData = () => {}
const getInitBData = () => {}
const getInitCData = () => {}

// or

const generateInitAData = () => {}
const generateInitBData = () => {}
const generateInitCData = () => {}

// or

const makeInitAData = () => {}
const makeInitBData = () => {}
const makeInitCData = () => {}
  1. 상수에도 의미 부여하기
Bad
setTimeout(someFunc, 86400000)

// and

.my_className {
  position: relative;
  left: 270px;
}

Good

const MILLISECONDS_IN_A_DAY = 24 * 60 * 60 * 1000
setTimeout(someFunc, MILLISECONDS_IN_A_DAY)

// and

.my_className {
  position: relative;
  left: calc(300px - 20px - 10px);
}
// padding, margin 등 계산한 값
  1. Index 접근 하지 말기
Bad
const userNameMap = new Map<number, string>()

for (const data of userNameMap){
  const id = data[0]
  const name = data[1]
}
Good
const userNameMap = new Map<number, string>()

for (const [id, name] of userNameMap){
  // ...
}
  1. destructuring 쓰기
    Bad
type Props = {
  onClose?: () => void
  pet?: GQLGetPet
}
export const PacsAddModal = (props: Props) => { ... }

Good

type Props = {
  onClose?: () => void
  pet?: GQLGetPet
}
export const PacsAddModal = ({ onClose, pet }: Props) => { ... }
  1. 의미 중복 지양하기
    Bad
type User = {
  userId: number
  userName: string
}

Good

type User = {
  id: number
  name: string
}
  1. default value 쓰기(short circuiting)
    Bad
const showPrettyName = (name?: string) => {
  return <div>{name ?? '2름'}</div>
}

Good

const showPrettyName =(name?: string = '2름') => {
  return <div>{name}</div>
}
  1. undefined와 0 확실히 구분하기 (보통 number type)
    Bad
export function isSafeNumberWithConstraints(
  value: number,
  options?: {
    minValue?: number
    maxValue?: number
  },
) {
  // limit max
  if (options?.maxValue && value > options.maxValue) return false

  // limit min
  if (options?.minValue && value < options.minValue) return false

  return true
}

Good

export function isSafeNumberWithConstraints(
  value: number,
  options?: {
    minValue?: number
    maxValue?: number
  },
) {
  // limit max
  if (options?.maxValue !== undefined && value > options.maxValue) return false

  // limit min
  if (options?.minValue !== undefined && value < options.minValue) return false

  return true
}
  1. enum 및 switch 사용하기
    Bad
type MyVar = {
  id: number
  status: number
}

const myVar = {
  id: 1
  status: 2
}

// ...

if (myVar.status === 1){
  // ...
} else if(myVar.status === 2){
  // ...
}

Good

enum EMyVarStatus {
  A = 1,
  B = 2,
  C = 3
}

type MyVar = {
  id: number
  status: EMyVarStatus
}

const myVar = {
  id: 1
  status: EMyVarStatus.B
}

// ...

// 1
const a = new Map<MyEnum, string>([
    [MyEnum.A, () => {}],
    [MyEnum.B, () => {}]
])

// 2
switch (myVar.status){
  case EMyVarStatus.A:
    // ...
  case EMyVarStatus.B:
    // ...
  default:
    // ...
}

Function
함수
1. 매개변수 3개 이상은 object로 (+destructuring)
Bad

const sumOfLengthOfRectangle 
  = (width: number, height: number, depth: number) => {
    return width + height + depth
}

Good

type RectangleSide = {
  width: number
  height: number
  depth: number
}

const sumOfLengthOfRectangle
 = ({width, height, depth}: RectangleSide) => {
  return width + height + depth
}
  1. 함수 단일책임 시키기(SRP) (=== 선언형)
    Bad
const emailClients = (clients: Client[]) => {
  clients.forEach((client) => {
    const clientRecord = database.lookup(client)
    if (clientRecord.isActive()) {
      email(client)
    }
  });
}

// or

const getChildrenAndGetSumOfAge = () => {
  const children = database.get('children')

  return sumOf(children.map((child) => child.age))
}

Good

const emailClients = (clients: Client[]) => {
  clients.filter(isActiveClient).forEach(email)
}

function isActiveClient(client: Client) {
  const clientRecord = database.lookup(client)
  return clientRecord.isActive()
}

// or

const getTotalAgeOfChildren = () => {
    return sumOf(getChildrenAges())
}

const getChildrenAges = () => {
  return database.get('children').map((child) => child.age)
}
  1. 코드 중복 제거하기
    설명 귀찮음

  2. 함수 인자에 _(underscore) 붙이기
    Bad

const someFunc = (child: Child, age: number) => {
  // ...
}

// or

const childrenAges = myChildren.map((child) => {
  return child.age
})

Good

const someFunc = (_child: Child, _age: number) => {
  // ...
}

// or

const childrenAges = myChildren.map((_child) => {
  return _child.age
})
⇒ 항상은 아니다.

Bad

const someFunc = ({_child, _age}: {_child: Child, _age: number}) => {
  // ...
}

// or

const someFunc = ({_child: child, _age: age}
  : {_child: Child, _age: number}) => {
    // ...
}

Good

const someFunc = ({child, age}: {child: Child, age: number}) => {
  // ...
}
  1. 함수 인자로 플래그처럼 쓰지 말기
    Bad
const createFile = (name: string, temp: boolean) => {
  if (temp) {
    fs.create(`./temp/${name}`)
  } else {
    fs.create(name)
  }
}

Good

const createTempFile = (name: string) => {
  createFile(`./temp/${name}`)
}

const createFile = (name: string) => {
  fs.create(name)
}
⇒ 하지만 이벤트 자체가 명확하지 않으면, 플래그 구분이 어딘가에는 결국 들어간다.

(이벤트 자체가 명확한 경우)

Bad

const handleButtonClick = (_myVar?: number) => () => {
  if(_myVar !== undefined){
    console.log(_myVar)
  }else{
    console.log('no!')
  }
}

// ...

<button
  onClick={handleButtonClick(5)}
>
  버튼1
</buttn>

<button
  onClick={handleButtonClick()}
>
  버튼2
</buttn>
Good
const handleNumberButtonClick = (_myVar: number) => () => {
    console.log(_myVar)
}

const handleButtonClick = () => {
    console.log('no!')
}

// ...

<button
  onClick={handleNumberButtonClick(5)}
>
  버튼1
</buttn>

<button
  onClick={handleButtonClick}
>
  버튼2
</buttn>
  1. Side Effect 피하기(순수 함수) 1
    Bad
export const SomeComponent = ({someA, someB}: Props) => {
  const [count, setCount] = useState<number>(0)

  const processSomething = () => {
    console.log(count, someA)
  }

  const handleButtonClick = () => {
        processSomething()
  }

  return (
        ...
  )
}

Good

export const SomeComponent = ({someA, someB}: Props) => {
  const [count, setCount] = useState<number>(0)

  const processSomething = (_count: number, _someA: number) => {
    console.log(_count, _someA)
  }

  const handleButtonClick = () => {
        processSomething(count, someA)
  }

  return (
        ...
  )
}

⇒ React 이벤트 핸들러에는 굳이..?

React에서 완벽한 순수함수를 하려면?

export const SomeComponent = ({someA, someB}: Props) => {
  const [count, setCount] = useState<number>(0)

  const processSomething = (_count: number, _someA: number) => {
    console.log(_count, _someA)
  }

  const handleButtonClick = (_count: number, _someA: number) => () => {
        processSomething(_count, _someA)
  }

  // 어차피 props 써야함
  return (
        <button onClick={handleButtonClick(count, someA)}>{...}</button>
  )
}
  1. Side Effect 피하기(순수 함수) 2
    Bad
const addItemToCart = (cart: CartItem[], item: Item): void => {
  cart.push({ item, date: Date.now() })
}

Good

const addItemToCart = (cart: CartItem[], item: Item): CartItem[] => {
  return cart.concat({ item, date: Date.now() })
}
  1. Immutable에 적극 활용하기
    Bad
let order = 0

if (condition1){
  order = 3
}else if(condition2){
  order = 1
}

console.log(order)

Good

const getOrderByCondition = () => {
    if (condition1){
        return 3
  } else if (condition2){
        return 1
    }

    return 0
}

const order = getOrderByCondition()
console.log(order)
  1. 조건문 캡슐화 (선언형)
    Bad
if (subscription.isTrial || account.balance > 0) {
  // ...
}

Good

const canActivateService = (_subscription: Subscription, _account: Account) => {
  return _subscription.isTrial || _account.balance > 0
}

if (canActivateService(subscription, account)) {
  // ...
}
  1. 부정 조건문 피하기
    Bad
const isEmailNotUsed = (email: string): boolean => {
  // ...
}

if (isEmailNotUsed(email)) {
  // ...
}

Good

const isEmailUsed = (email): boolean => {
  // ...
}

if (!isEmailUsed(node)) {
  // ...
}
  1. 과한 최적화는 피하기
    Bad
const length = myList.length
for (let i = 0; i < length; i++ ) { ... }

Good

for (let i = 0; i < myList.length; i++ ) { ... }
profile
풀스택 웹개발자👩‍💻✨️

0개의 댓글