-
Notifications
You must be signed in to change notification settings - Fork 3
[FE] TypeScript 컨벤션
최혜령 edited this page Nov 8, 2023
·
3 revisions
- 함수 선언문 vs 표현식
- 다른 함수 선언에도 표현식을 사용했기 때문에 코드의 일관성 유지를 위해 컴포넌트를 작성할 때에도 함수 표현식을 사용했습니다.
- type vs interface vs inline
- 네이밍 방식:
{컴포넌트명}Props
-
VFC, FC, PropsWithChildren
- 일반적인 경우에는
PropsWithChildren
을 사용하고 외부에선 타입 추론이 안 되도록 감추고 내부에서만 사용하고 싶은 prop이 있을 경우React.FC
와PropsWithChildren
을 사용합니다.-
React.FC
를 사용하면Children
타입을 명시할 필요 없음 React.FC<T> = T & {children?:ReactNode}
-
type Private<T> = T & { __private__ : boolean } interface MyProps {} const Component:React.FC<MyProps> = (props:PropsWithChildren<Private<MyProps>>) => { const {__private__} = props; } const obj = {__private__.: true} <Component __private__ = {}/>
- 일반적인 경우에는
-
Children, render메서드/컴포넌트 반환 타입
-
JSX.Element vs React.ReactElement vs ReactNode
type ReactNode = ReactElement | string | number | ReactFragment | ReactPortal | boolean | null | undefined;
-
- Event Handler vs Event
const handleClick: React.MouseEventHandler<HTMLButtonElement> = (event) => { /*...*/ };
// vs
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => { /*...*/ };
- import 방식
-
React.MouseEventHandler
vsMouseEventHandler
-
// useState 예시
// 타입과 초기값을 지정하는 방식
const [data, setUser] = useState<User | undefined>(undefined);
const [data, setUser] = useState<User | null>(null);
const [user, setUser] = useState<User>({});
const [user, setUser] = useState<boolean>(true);
의도한 대로 타입추론이 되는 경우 타입 생략 vs 데이터가 반환되는 훅의 경우 타입 지정하기
- MutableRefObject vs RefObject
// ref의 용도에 맞게 오버로딩 된 타입을 활용한다
// current를 변경하고 싶은 경우
const ref = useRef() // MutableRefObject
const ref = useRef(3) // MutableRefObject
const ref = useRef<number>() // MutableRefObject ✅
// current를 변경하고 싶지 않은 경우
const ref = useRef<number | null>(null) // RefObject ✅
- 네이밍 컨벤션
- Props 타입 네이밍 →
${컴포넌트 이름}Props
- Props 타입 네이밍 →
- 디렉토리 구조: 도메인 별 구분
📦types
┣ 📂assets
┃ ┗ 📜assets.d.ts
┣ 📂common
┃ ┣ 📜errorBoundary.ts
┃ ┗ 📜utility.ts
┣ 📂food
┃ ┣ 📜client.ts
┃ ┗ 📜remote.ts
┗ 📂review
┃ ┣ 📜client.ts
┃ ┗ 📜remote.ts
- 선언 위치: Props → 같은 컴포넌트 파일 내의 컴포넌트 위, 나머지 → types 디렉토리
- import/export 방식
- 타입스크립트와 별개로도 모듈 import/export 규칙 논의해보기
-
Type-Only Import and Exports 사용 여부? 🙆♂️
- 빌드 속도, 타입 안정성, 가독성 향상
✅
import type { SomeThing } from "./some-module.js";
export type { SomeThing };
vs
❎
import { SomeThing } from "./some-module.js";
export type SomeThing;
// 예시
type Food = {
id: number;
name: string;
imageUrl: string;
purchaseUrl: string;
};
export type { Food };
- API 호출 로직에서 Request / Response 데이터를 다루는 방식
- /src/types/${domain}/reomote.ts에서 관리
interface GetSomethingReq {
}
interface GetSomethingRes {
}
- Request, Response 데이터의 타입을 나누어 Interface로 선언
- TS 컴파일을 위해 어떤 loader를 사용하고 있는지와 선택 이유
- 참고) babel-loader, ts-loader, esbuild-loader
-
@babel/preset-typescript
: ts-loader 없이 typescript 트랜스파일링 가능 -
ForkTsCheckerWebpackPlugin
: 빌드 과정에서 type 체크 가능(ts-loader 보다 뛰어난 속도)
- 설정 기준과 설정한 항목들에 대한 이해
{
"compilerOptions": {
"target": "es6",
"lib": ["dom", "dom.iterable", "ESNext"], // 컴파일에 포함할 표준 라이브러리를 지정합니다 (DOM 관련 API들)
"jsx": "react-jsx",
"module": "ESNext", // 컴파일에 사용할 모듈 시스템을 지정합니다 (ECMAScript Modules)
"moduleResolution": "node", // 모듈 해석 전략을 지정합니다 (Node.js 스타일)
"baseUrl": ".",
"resolveJsonModule": true, // JSON 모듈을 가져오도록 허용합니다
"allowJs": true, // JavaScript 파일도 컴파일하도록 허용합니다
"declaration": true, // .d.ts 형태의 선언 파일을 생성합니다
"outDir": "./lib", // 생성된 .d.ts 선언 파일의 출력 디렉토리를 지정합니다
"noEmitOnError": true, // 오류 발생 시 TypeScript 출력물을 생성하지 않도록 설정합니다
"isolatedModules": true, // 다른 타입의 import를 같은 모듈에서 허용하지 않습니다
"allowSyntheticDefaultImports": true, // 'import x from "module-name"' 형태의 모듈을 허용합니다
"esModuleInterop": true, // ESMInterop을 위해 __importStar와 __importDefault 도우미를 생성합니다
"forceConsistentCasingInFileNames": true, // 파일 이름에서 일관된 대소문자를 강제합니다 (대소문자를 구분하는 경로를 적용합니다)
"strict": true, // 엄격한 타입 체크 옵션을 활성화합니다
"noImplicitAny": true, // 암시적으로 'any' 타입을 허용하지 않습니다
"noFallthroughCasesInSwitch": true, // switch문에서 모든 case에 'break' 또는 'return' 문이 없을 경우 오류를 발생시킵니다
"skipLibCheck": true, // 선언 파일 (*.d.ts)의 타입 체크를 건너뜁니다
"paths": { // 모듈 이름에 대한 경로 매핑 별칭을 지정합니다 (예: "@/*"는 "src/*"를 가리킵니다)
"@/*": ["src/*"]
}
},
"include": ["src"],
"exclude": ["dist", "./src/**/*.stories.tsx"]
}
뿌듯한 부분, 도움이 필요한 부분, 우리 팀의 팁 등등