> For the complete documentation index, see [llms.txt](https://toktokhan.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://toktokhan.gitbook.io/docs/basic-guides/convention-archive/code-style.md).

# code style

## :label: Naming: Case

기본적인 선언에 대한 네이밍 규칙입니다.

### 변수: camelCase

```tsx
let exampleVariable: null | number = null
let exampleArray: number[] = [];
```

### 상수, 상수 집합: SNAKE\_CACE

```tsx
const MAX_LENGTH = 5;
const TITLES = ["제목1", "제목2", "제목3"];
```

### 함수: camelCase

<pre class="language-tsx"><code class="lang-tsx">function increaseCount() {...}
<strong>const decreaseCount = () => {...}
</strong></code></pre>

### 매개변수: camelCase

```tsx
function playAnimation() {...}
const  = () => {...}
```

### 클래스: PascalCase

```tsx
class Animal {...}
```

### 타입: PascalCase

```tsx
interface Apple {...}
type TreeBug = {...}
```

### 컴포넌트: PascalCase

```tsx
const Post () => <div>...</div>
function PostDetail () {...}
class PostList {...}
```

***

## :label: Naming: Special Case

특수한 상황의 선언에 대한 네이밍 규칙입니다.

관행적인 네이밍을 사용하거나 접두 / 접미사를 붙여 역할을 명확하게 해주는 부분에 초점을 맞춰보세요.

### Props

`Props` 네이밍은 접미사(suffix)로 `Props` 를 붙여줍니다.

```typescript
interface SocialButtonProps {...}

const SocialButton = ({...}: SocialButtonProps) => {...}
```

### Hook / Hoc / Context / Provider

`Hooks` 네이밍은 접두사(prefix)로 `use` 를 붙여줍니다.

```tsx
function useSize() { ... }
```

`Hoc` 네이밍은 접두사(prefix)로 `with` 를 붙여줍니다.

```tsx
function withAppProvider(AppComponent: FC<AppProps>) {...}
```

`Context` 네이밍은 접미사(suffix)로 `context` 를 붙여줍니다.

```tsx
const { show, close } = useModalContext(...);
```

`Provider` 네이밍은 접미사(suffix)로 `provider` 를 붙여줍니다.

```tsx
const ModalProvider = () => {...}
```

### Api / React Query

`Api class` 네이밍은 접미사로 `api` 를 붙여 줍니다.

```typescript
class ProductApi {
    getList = async(...) => {...};
    createProduct = async(...) => {...};
}
```

`Api class 의 Method(요청함수)` 는 되도록 method 별 관행적인 이름으로 네이밍 합니다.

> method 별 관행적인 이름
>
> * GET -> `get`
> * POST -> `create`
> * PATCH, PUT -> `update`
> * DELETE -> `delete`

```tsx
class ProductApi {
  createProduct = async (...) => {
    const { data } = await this.axios({
      method: 'POST'
      ...
    });
    return data;
  };
}
```

단, `함수의 특정 행동이 부각`되길 원하는경우 그 행동으로 네이밍 합니다.

```tsx
class ProductApi {
  validateSoldOut = async (...) => {
    const { data } = await this.axios({
      method: 'GET'
      ...
    });
    return data;
  };
}
```

`network 관련 api 의 요청과 응답 타입 정의`는 일반적인 타입정의와 구분하여 네이밍 합니다.

`dto 타입`의 네이밍은 접미사로 `Dto` 를 붙여줍니다.

```tsx
interface UpdateProdcutDto {
  title?: string;
  description?: string;
}
```

`model` 타입의 네이밍은 접미사로 `Model` 을 붙여줍니다.

```tsx
interface ProductModel {
  title: string;
  description:string;
  createdAt: string;
}
```

사용시엔 아래처럼 사용 합니다.

```tsx
class ProductApi {
  updateProduct = async (req: UpdateProductDto): Promise<ProductModel> => {...};
  ...
}
```

{% hint style="info" %}
**dto, model 이 뭔가요?**

**dto** 는 Data Transfer Object 의 약자로, 통신을 위한 데이터 객체를 의미합니다. 보일러 플레이트에선  **요청 타입에** 해당합니다.

**model** 은 프론트 코드에서 서버의 데이터 구조를 표현하기 위한 타입 명명이며, 보일러 플레이트에선 주로 **응답 타입**에 해당합니다.
{% endhint %}

재사용성, 유지보슈를 위해 React Query의 hooks를 custom hook 으로 감싸서 사용합니다.

`react query 의 custom hooks 네이밍은`  api 메소드 이름을 기반으로 작성하고, 접두사에는 `use` 를 붙여 줍니다.

`useQuery 의 custom hook` 은 접미사에 `Query` 를 붙여줍니다.

```tsx
// 함수 이름: getProductList
function useGetProductListQuery(...) {
  return useQuery(...);
}
```

`useInfiniteQuery 의 custom hook` 은 접미사에 `InfiniteQuery` 를 붙여줍니다.

```tsx
// 함수 이름: getProductList
function useGetProductListInfiniteQuery(...) {
  return useInfiniteQuery(...);
}
```

`useMutation 의 custom hook` 은 접미사에 `Mutation` 를 붙여줍니다.

```tsx
// 함수 이름: getProductList
function useUpdateProductMutation(...) {
  return useMutation(...);
}
```

react query 는 query key 가 필수적으로 필요합니다. query key 의 세부적인 조정을 위해 함수로 작성하되, 예외적으로 상수 선언과 같은 규칙인 `UPPER_SNAKE_CASE` 로 작성합니다.

`query key`의 접미사로 `QUERY_KEY` 를 붙여 줍니다.

```tsx
const PRODUCT_API_QUERY_KEY = {
  GET_LIST: (params?) => params ? ['prodcut-list', params] : ['product-list']
};
```

### React Hook Form

재사용성, 유지보수를 위해 React Hook Form 의 hook 를 custom hook 으로 감싸서 사용합니다.

`react hook form 의 custom hooks 네이밍은` 는 접두사는 `use` 접미사는 `Form` 을 붙여줍니다.

```tsx
const useLoginForm = (...) => {
  return useForm(...);
};
```

`React Hook Form` 을 사용할 때  유효성 검사를 돕는 라이브러리로 `Yup` 를 같이 사용합니다.

yup 을 사용하여 만든 **유효성 검사를 정의하는 객체**는 접미사로 `schema` 를 붙여줍니다.

```typescript
// yup 로 생성한 유효성 검사를 돕는 객체
const loginSchema = yup.object({ ... });

const useLoginForm = (...) => {
  return useForm(...);
};
```

## :ribbon: Code Style: Naming

네이밍시 권장되는 규칙입니다.

### 명확한 이름 작성하기

`info` / `data`, `특정 숫자`와 같은 모호한 이름 보다 **좀 더 명확한 이름으로 작성**을 고민해보세요.

```tsx
// bad
const [index1, index2] = useState();
const [someData, setSomeData] = useState();

// good
const [pageIndex, setPageIndex] = useState(0);
const [selectedCategory, setSelectedCategory] = useState('all');
```

### 불필요한 문맥 제거하기

객체나 특정 함수 내에서 불필요하게 중복되는 부분은 제거하는것이 좋습니다.

```tsx
// bad
const car = { carName: 'tok', carColor: 'black' };
// good
const car = { name: 'tok', color: 'black' };
```

### 구조분해로 인해 명시적이지 않은 값은 재할당으로 명확히 표현해주기

```typescript
// bad
const ResultScreen = () => {
  const { isOpen, onClose, onOpen } = useDisclose();
  ...
}

// good
const ResultScreen = () => {
  const {
    isOpen: isOpenResultModal,
    onClose: onCloseResultModal,
    onOpen: onOpenResultModal,
  } = useDisclose();
  ...
}
```

### 함수는 동사로 작성하기

```tsx
// bad
const musicPlayer = () => {...}
// good 
const playMusic = () => {...} 
```

### Prop 네이밍은 내려주는 입장이 아닌 컴포넌트 입장에서 네이밍하기

더욱 확장성 있는 네이밍이 됩니다.

🧭 **Example**

```tsx
// Bad
<Article 
  dogName={dogName}
  dogDescription={dogDescription}
  likeRequest={likeRequest} 
/>

// Good
<Article 
  title={dogName}
  contents={dogDescription}
  onLike={likeRequest} 
/>
```

### 관행적인 네이밍 방식 사용하기

#### 컴포넌트가 props 에서 event 함수를 받을 때는 on.... 접두사를 붙여 네이밍 하기

```tsx
interface Props {
    onClick:() => void
}
const Component = ({ onClick }: Props) => {...}
```

#### 컴포넌트에게 넘겨지는 event 함수를 작성할 때는 handle... 접두사를 붙여 네이밍 하기

```tsx
const Parent = () => {
  const handleClick = (event) => {...}
    
  return (
    <Children onClick={handleClick}/>
  )
}
```

#### boolean 관련된 값, 함수는 is, can, has, should 를 사용해주세요

```tsx
const isMobile = breakpoint === "base"
const isSelected = (id: number): boolean => {...}
const hasGreen = (colors: string[]): boolean => {...}
const canEdit = user.access === "edit"
```

***

## :ribbon: Code Style: Object

객체에서 권장되는 규칙입니다.

### 구조 분해 할당을 사용하여 반복되는 코드를 줄여주세요

```tsx
// Bad
const item = data.item
const isValid = data.isValid

// Good
const { isValid, item } = data
```

### 키값과 벨류에 들어갈 변수명이 동일할 경우 JS 문법으로 더욱 깔끔하게 처리 가능합니다.

```tsx
const item = {
  id: id // bad 
  title, // good
  decription,
}
```

***

## :ribbon: Code Style: If Statement

조건문에서 권장되는 규칙입니다.

### 조건은 캡슐화 해주세요

```tsx
//Bad
if(!!users.find(isActiveUser) && date.now() > date.createdAt.getTime()) {...}

//Good
const hasActiveUser = !!user.find(isActiveUser);
const isBeforeFromNow = date.now() > date.createdAt.getTime()

if(hasActiveUser && isBeforeFromNow) {...}
```

### else 문은 되도록 피해주세요

```tsx
// 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)

```

### 예외케이스를 우선적으로 리턴해주세요

```tsx
// 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]);
```

***

## :ribbon: Code Style: Function

함수에서 권장되는 규칙입니다.

### 하나의 함수는 한가지 일만 하게 해주세요

```tsx
// 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();
}
```

### 되도록 순수함수로 작성해주세요

```tsx
//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개 이하로 작성해주세요. 많아진다면 하나의 객체로 넘겨줄 수 있습니다.

```typescript
// Bad
function createMenu(title: string, body: string, buttonText: string, cancellable: boolean) {
  // ...
}
createMenu('Foo', 'Bar', 'Baz', true);

//Good

function createMenu(options: { title: string, body: string, buttonText: string, cancellable: boolean }) {
  // ...
}
createMenu({
  title: 'Foo',
  body: 'Bar',
  buttonText: 'Baz',
  cancellable: true
});
```

***

## :ribbon: Code Style: Component

컴포넌트에서 권장되는 규칙입니다.

### 상속 보다 조합

컴포넌트 작성시, 자식을 많이 가지고 있을수록 prop drilling 을 마주하기 쉬워집니다.

그럴땐 자식을 많이가지는 거대한 컴포넌트 보다도, 컴포넌트 합성을 통해서, 관심사를 명확히 분리하고 prop drilling 을 피해 보세요

🧭 **Example**

```tsx
// bad
<PostDetail
  title={title} // header props
  likes={likes}
  onLike={onLike}
  onShare={onShare}
  created={created}
  description={description} // other props...
  onBack={onBack}
  onSubmit={onSubmit}
/>

// good
<PostDetail
  header={
    <PostHeader
      title={title} // header props
      likes={likes}
      onLike={onLike}
      onShare={onShare}
      created={created}
    />
  }
  description={description} // other props...
  onBack={onBack}
  onSubmit={onSubmit}
/>;

```

#### 참고

* <https://ko.legacy.reactjs.org/docs/composition-vs-inheritance.html>
* <https://fe-developers.kakaoent.com/2022/220731-composition-component/>

### 추상화 레벨 맞추기

컴포넌트를 분리해도 추상화 레벨이 맞지 않으면  파악이 어려울 수 있습니다.

한 눈에 구조 파악이 가능하도록 추상화 레벨을 맞춰보세요.

🧭 **Example**

```tsx
// bad
<>
  <Title>우리팀을 소개합니다.</Title>
  <div>
    {members.map((member) => (
      <Member data={member} />
    ))}
  </div>
  <Comments />
  {rating !== 0 && (
    <>
      <Agreement />
      <Button rating={rating} />
    </>
  )}
</>;


// good
<>
  <Title>우리팀을 소개합니다.</Title>
  <Members />
  <Comments />
  <AgreementButton show={rating !== 0} />
</>;
 
```

### 파일 내 선언 순서 지키기

<figure><img src="/files/LForo3swAoqomey5gDlI" alt=""><figcaption></figcaption></figure>

{% tabs %}
{% tab title="1. Import" %}
&#x20;**파일 최 상단에 오지 않으면 문법상 오류**가 발생합니다. `Prettier`에 의해 **자동으로 순서가 정리**됩니다.
{% endtab %}

{% tab title="2. Constants" %}
파일 내부에서 사용 되는 상수는 **import 아래 작성**합니다.

만약 이 상수가 다른 파일에도 중복사용 된다면 따로 **파일을 분리하여 작성하는걸 고려**해보세요.
{% endtab %}

{% tab title="3. Props Type" %}
`Props`를 받아서 사용하는 **컴포넌트 상단과 가깝게 작성**하여 수정 및 확인에 용이하게 합니다.
{% endtab %}

{% tab title="4. Component" %}
앞서 필요한 부분이 전부 선언되었기에 이 단계에서 작성합니다.
{% endtab %}

{% tab title="5. Export" %}
특별한 이유가 없다면 현재 컴포넌트를 마지막 줄에서 export default로 작성해줍니다.
{% endtab %}
{% endtabs %}

### 컴포넌트 내부 선언 순서 지키기

특별한 상황이 아니면 아래 순서를 지켜주세요

<figure><img src="/files/En7PuXgpgMmqs5VTWRn1" alt=""><figcaption></figcaption></figure>

{% tabs %}
{% tab title="React Hooks" %}
`useState`, `useRef`와 같은 **React에서 기본적으로 제공하는 hooks** 입니다.

다만 `useEffect`의 경우 하단에서 작성하는데,  `Side Effect` 탭에서 사유를 좀 더 상세하게 서술하겠습니다.
{% endtab %}

{% tab title="Custom Hooks" %}
**설치한 Library의 hooks와 직접 구현한 Custom Hooks**입니다.

`state`와 같이 **필요한 부분을 Props로 전달하여 사용하는 경우도 많기** 때문에 일반적으로 React Hooks 아래에 작성됩니다.
{% endtab %}

{% tab title="Variables" %}
상수가 아닌 **특정 상태(state)에 따라 변하는 변수**들이 일반적으로, `state` 아래에 선언하여 사용합니다.

또한 **계산이 무거운 값 들은** `useMemo` **로 최적화**를 고려해보세요.
{% endtab %}

{% tab title="Functions" %}
함수 또한 파라미터로 전달받기도 하지만 **state와 변수를 그대로 참조하여 쓰는 경우**도 있기 때문에 state와 변수 아래 선언합니다.

필요에 따라 유틸성 / 순수함수들은 **컴포넌트 외부로 분리하는 것도 고려**해보세요.
{% endtab %}

{% tab title="Side Effects" %}
`useEffect`로 관리되는 **Side Effect**는 **Component return 바로 위에 작성**합니다.

**특정 상태나 함수에 의존하여 실행되어야 하는 로직들**이 대부분이기 때문에 상태나 함수의 하단에 작성되어야 합니다.
{% endtab %}
{% endtabs %}

### **useEffect 동작에 대한 주석처리**

사용되는 모든 `useEffect` Hooks 를 추상화하려면 Custom Hooks 로 관리 해야합니다.

이는 번거로울 수 있고, 재사용이 적은 경우라면 오히려 응집도를 낮추는 코드가 될 수 있습니다.&#x20;

따라서, `useEffect` 를 사용할땐 아래와 같은 **주석처리로 간단히 추상화 해주세요**

```typescript
const Component = () => {
  // For: Initailize State 
  React.useEffect(() => {...})
  return <div>...</div>;
};

```

## :ribbon: Code Style: Apis

서버와 통신하는 api 를 선언 할시 지켜야할 규칙입니다. 더 상세한 설명은 [api 문서](/docs/basic-guides/convention/apis.md)에서 확인 할 수 있습니다.

### network 요청을 하는 api 는 axios instance 를 받는 class 로 선언하기

base-url, interceptor 를 설정할 수 있는 axios instance 를 받는 class 로 관리함으로써, 검색과 이후 수정 사항 관리에 수월 합니다.

```typescript
import instance from '@/configs/axios/instance';

export class ExampleApi {
  axios: AxiosInstance = instance; // 기본값으로 미리 정의된 instance 를 할당합니다.
  constructor(axios?: AxiosInstance) {
    if (axios) this.axios = axios;
  }

  getList = async (...) => {
    const { data } = await this.axios({
      url: `/v1/example`, // base url 은 instance 에서 설정합니다.
      ...
    });
    return data;
  };

```

### class 작성 파일 하단에 class instance 를 생성해서 export 하기

일반적으로 `axios instance` 설정은 크게 바뀔 일이 없기 때문에 하단에 `class instance` 를 생성 해서 `export` 해줍니다.

```tsx
export class ExampleApi {...}

export default const exampleApi = new ExampleApi()
```

### method 의 타입정의는 Dto 와 Model 로 구분하여 관리하기

&#x20;데이터 요청을 위한 타입정의는 `dto` 로, 서버로부터 받아와 사용하는 데이터의 타입정의는 `model` 로 다른 타입들과 구분해 줍니다. 특히 응답 타입은 정의하지 않을시 `any` 타입이 되므로 반드시 작성 해줍니다.

```typescript
export class ExampleApi {
  getList = async (params?: GetExampleDto): Promise<ExampleModel[]> => {...};
}
```

### react query 의 query-key 는 함수로 작성하기

query-key 에 기반한 cache data 를 조금 더 세밀하게 관리 할 수 있습니다.

<pre class="language-tsx"><code class="lang-tsx">const EXAMPLE_API_QUERY_KEY = {
<strong>  GET_LIST: (params) => ['example-list', params],
</strong>  GET_BY_ID: (params) => ['example-by-id', params],
};
</code></pre>

### query-key 는 custom hook 상단에 작성하기

custom hook 선언과 query-key 선언을 한곳에서 관리합니다.

```tsx
const EXAMPLE_API_QUERY_KEY = {
  GET_LIST: (params) => ['example-list', params],
  GET_BY_ID: (params) => ['example-by-id', params],
};

const useGetExampleListQuery = (...) => useQuery(...)
const useGetExampleGetByIdQuery = (...) => useQuery(...)
```

### react query custom hook 을 선언할 땐 기존 커스텀 타입 정의 사용하기

커스텀 타입정의는 해당 `query` 나 `mutation` 이 받는 함수의 타입을 기반으로, `param` 과 `onSuccess` 와 같은 `option` 에 대한 타입정의를 생성해 줍니다.

`useQuery` 는 [`UseQueryParams`](/docs/basic-guides/convention/types/boilerplate/modules.md#usequeryparams) 를 사용합니다.

```typescript
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 이 가능해집니다.
    }
  }
})
```

`useMutation` 는 [`UseMutationParams`](/docs/basic-guides/convention/types/boilerplate/modules.md#usemutationparams) 를 사용합니다.

```typescript
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개 이하로 작성하기

```tsx
export class ExampleApi {
  // bad : 커스텀 타입인 UseQueryParams 이 제대로 작동하지 않을 수 있습니다.
  getList = async (offset: number, limit: number) => {...};
  // good
  getList = async (params: {offset: number, limit: number}) => {...};
}
```

***

## :ribbon:Code Style: Utils

### 전역적으로 사용하는 util 은 test 코드를 포함하기

전역적으로 사용하는 함수의 경우엔 재 사용성이 높고, 타인이 사용할 가능성이 높기 때문에 검증이 필수적입니다.

테스트 코드를 통해 브라우저를 실행하지 않고도 검증을 확인 할 수 있으며, 결과값을 알 수 있기 때문에 문서화 효과를 누릴 수 있습니다.

```tsx
export const formatNumberKR = (num: number) => num.toLocaleString('ko-KR');
```

```tsx
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');
  });
});

```

***

## :ribbon:Code Style: Types

전역적으로 사용하는 Utility(Generic) 타입은 예시코드를 사용하기

전역적으로 사용하는 utility 타입의 경우엔 타인이 사용할 가능성이 높기 때문에, 미리 결과를 알 수 있는 예시코드를 포함해 줍니다.

```typescript
// type Example = ItemOf<['a', 'b', 'c']>;
// Example = "a" | "b" | "c"

export type ItemOf<T extends Array<any> | readonly any[]> = T[number];
```

***

## Reference

클린 코드에 관심이 많으신가요?

저희의 코드 컨벤션은 여러 문서 중, 아래 두 문서를 주로 참고하여 작성되었습니다.

### [Clean Code TypeScript](https://github.com/738/clean-code-typescript)

> **Comment\_**\
> \
> 타입스크립트는 자바스크립트의 Super Set 이듯이,
>
> 위의 게시물도 우리 클린코드의 Super Set 입니다.
>
> 꼭 확인해 보세요!

### [TOSS: 실무에서 바로 쓰는 Frontend Clean Code](https://toss.im/slash-21/sessions/3-3)

> **Comment\_**\
> \
> 똑개 코드원칙에서 소개된 **추상화, 단일책임, 응집도**에 대해 친절하고 자세히 설명되어있는 영상입니다
>
> 길지 않으니 꼭 시청해 주세요

***

## Reference: TokTokHan

### [React 코드를 더 잘 작성하고 싶다면?](/docs/onborading/growing-up/react.md)

> **Comment\_**\
> \
> 똑개에서 추려본 리액트 공식문서의 핵심글들을 위 게시물에서 확인해보세요!

### [TS, interface 와 type 만 쓰고 계시진 않나요?](/docs/onborading/growing-up/ts-skill.md)

> **Comment\_**\
> \
> 타입스크립트의 다양한 사용방법을 확인해 보고, 코드를 더욱 안전하게 작성해보세요

### [Test Code 시작 가이드](/docs/onborading/growing-up/console.log-testing.md)

> **Comment\_**\
> \
> 테스트 코드를 우리 개발 환경에서 빠르게 시작하고 싶다면 위 게시물을 확인해 보세요

### 컨벤션 문서가 조금 어렵게 느껴지신다면

> Basic 가이드의 다른 탭을 확인해보세요.
>
> Apis, Type 주제별로 조금 더 상세한 설명과 함께 작성되어있습니다.

### 보일러 탬플릿엔 어떤 기능들이 있나요?

> Boiler Template 게시물을 확인해보세요.
>
> 미리 구현된 기능들을 사용하며, 개발해보세요
