TypeScript์ ์ ๋ฌธํ๋ React ๊ฐ๋ฐ์๋ฅผ ์ํ ์นํธ์ํธ(Cheetsheets)

์น ๋คํ๋จผํธ | ์์ดํ | ํ๋ก์ ํธ์ ๊ธฐ์ฌํ๊ธฐ | ์ง๋ฌธํ๊ธฐ
๐ ๋ณธ ๋ฆฌํฌ์งํ ๋ฆฌ๋ @ryan_kim_kr์ ์ํด ๊ด๋ฆฌ๋๊ณ ์์ต๋๋ค. ๊ฐ๋ฐ์๋์ด React์ ํจ๊ป TypeScript๋ฅผ ์ฌ์ฉํด๋ณด๊ณ ์ ํ์๋ค๋ ์ ๋ง ๊ธฐ์ ์์์ด๊ตฐ์! ์๋ชป๋ ๋ถ๋ถ์ด ๋ฐ๊ฒฌ๋์ด ์์ ์ด ํ์ํ๊ฑฐ๋ ๋๋ฝ๋ ๋ถ๋ถ์ด ์๋ค๋ฉด ๊ฐ์ ๋์ด์ผ ํ ์ฌํญ์ ์ด์ ๋ฑ๋กํด ์ฃผ์๊ธฐ ๋ฐ๋๋๋ค. ๐
- ๊ธฐ์ด ์นํธ์ํธ(The Basic Cheatsheet)๋ React ๊ฐ๋ฐ์๊ฐ React app์์ TS ์ฌ์ฉ์ ์์ํ๋ ๊ฒ์ ๋์์ ์ฃผ๊ธฐ ์ํ ๋ด์ฉ์ด ์ฃผ๋ฅผ ์ด๋ฃน๋๋ค.
- ๋ชจ๋ฒ ์ฌ๋ก(Best Practices)๋ผ๊ณ ์ฌ๊ฒจ์ง๋, ๋ณต์ฌ + ๋ถ์ฌ๋ฃ๊ธฐ ๊ฐ๋ฅํ ์์
- ๊ธฐ๋ณธ์ ์ธ TS Types ์ฌ์ฉ๋ฒ๊ณผ ์ค์ ๋ฐฉ๋ฒ
- ์์ฃผ ๋ฌป๋ ์ง๋ฌธ(FAQ)์ ๋ํ ๋ต๋ณ
- Generic type logic์ ๊น์ด ๋ค๋ฃจ์ง ์์ต๋๋ค. ๊ทธ ๋์ , ์ด์ฌ์๋ค์ ์ํด ๊ฐ๋จํ ํธ๋ฌ๋ธ์ํ ๊ธฐ์ ๋ค์ ์๊ฐํฉ๋๋ค.
- ๊ธฐ์ด ์นํธ์ํธ๋ ๊ฐ๋ฐ์๊ฐ TypeScript์ ๋ํด ๋๋ฌด ๋ง์ ๊ณต๋ถ๋ฅผ ํ์ง ์๊ณ ์๋ ์๊ฐ ํจ์จ์ ์ผ๋ก React ๊ฐ๋ฐ์ TypeScript๋ฅผ ๋น ๋ฅด๊ฒ ์ฌ์ฉํ ์ ์๋๋ก ๋๋ ๋ฐ ๊ทธ ๋ชฉ์ ์ด ์์ต๋๋ค.
- ๊ณ ๊ธ ์นํธ์ํธ(The Advanced Cheatsheet)๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ type utilities/functions/render prop/higher order copmonents ๋๋ TS+React ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ฑํ๊ณ ์ ํ๋ ๊ฐ๋ฐ์๋ฅผ ์ํด generic types์ ๊ณ ๊ธ ์ฌ์ฉ๋ฒ์ ๋ํ ์ดํด๋ฅผ ๋์ต๋๋ค.
- ์ ๋ฌธ์ ์ธ ๊ฐ๋ฐ์๋ค์ ์ํ ๋ค์ํ ํ๊ณผ ์๋ น๋ค์ ์๊ฐํฉ๋๋ค.
- DefinitelyTyped์ ๊ธฐ์ฌํ๊ธฐ ์ํ ์กฐ์ธ์ ๋๋ฆฝ๋๋ค.
- ๊ณ ๊ธ ์นํธ์ํธ๋ ๊ฐ๋ฐ์๊ฐ TypeScript๋ฅผ ์ต๋ํ ํ์ฉํ ์ ์๋๋ก ๋๋ ๋ฐ ๊ทธ ๋ชฉ์ ์ด ์์ต๋๋ค.
- ๋ง์ด๊ทธ๋ ์ดํ
์นํธ์ํธ(The Migrating Cheatsheet)๋ ๋๊ท๋ชจ ์ฝ๋๋ฒ ์ด์ค๋ฅผ JS ๋๋ Flow์์ TypsScript๋ก ์ ์ง์ ์ผ๋ก ๋ง์ด๊ทธ๋ ์ด์
ํ๋ ๊ฒ์ ๋ํ ๊ฒฝํ์์ ์กฐ์ธ์ ์ป๋๋ฐ ๋์์ ์ค๋๋ค.
- ์ฐ๋ฆฌ๋ ์ฌ๋ฌ๋ถ์ด ๋ง์ด๊ทธ๋ ์ด์ ์ ํ๋๋ก ์ค๋ํ๋ ค๋ ๊ฒ์ด ์๋๋ฉฐ, ์ด๋ฏธ ๊ทธ๋ ๊ฒ ํ๊ณ ์ ๊ฒฐ์ ํ ์ฌ๋๋ค์ ๋๊ณ ์ ํฉ๋๋ค.
โ ๏ธ ์ด ์นํธ์ํธ๋ ์๋กญ๊ฒ ๋ง๋ค์ด์ง ์นํธ์ํธ ์ ๋๋ค. ๋ฐ๋ผ์ ๋์์ ์ฃผ๊ณ ์ ํ๋ ๋ชจ๋ ๋ถ๋ค์ ํ์ํฉ๋๋ค.
- HOC ์นํธ์ํธ(The HOC Cheatsheet)๋ ์์์ ํจ๊ป HOC๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ์๋ ค์ค๋๋ค.
- Generics์ ๋ํ ์ดํด๊ฐ ์ ํ๋์ด์ผ ํฉ๋๋ค.
โ ๏ธ ์ด ์นํธ์ํธ๋ ์๋กญ๊ฒ ๋ง๋ค์ด์ง ์นํธ์ํธ ์ ๋๋ค. ๋ฐ๋ผ์ ๋์์ ์ฃผ๊ณ ์ ํ๋ ๋ชจ๋ ๋ถ๋ค์ ํ์ํฉ๋๋ค.
๋ชฉ์ฐจ ํ์ฅํ๊ธฐ
- React์ ๋ํ ์ถฉ๋ถํ ์ดํด
- TypeScript Types์ฃผ์ ์ ๋ํ ์ดํด (2ality's guide๋ฅผ ์๊ณ ์์ผ๋ฉด ๋ฌธ์๋ฅผ ์ดํดํ๋๋ฐ ๋์์ด ๋ฉ๋๋ค. ๋ง์ฝ TypeScript๋ฅผ ์ฒ์ ์ ํ๋ ๋ถ์ด๋ผ๋ฉด,chibicodeโs tutorial๋ฅผ ์ฐธ๊ณ ํด ๋ณด์ธ์.)
- the TypeScript section in the official React docs ์ฝ๊ธฐ
- the React section of the new TypeScript playground ์ฝ๊ธฐ (์ ํ์ฌํญ: the playground's Example Section์ 40+ examples ๋จ๊ณ๋ฅผ ์ํํด ๋ณด๊ธฐ)
์ด ๊ฐ์ด๋๋ ๋
์๊ฐ ๊ฐ์ฅ ์ต์ ๋ฒ์ ์ TypeScript์ React๋ฅผ ์ฌ์ฉํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ์ด์ ๋ฒ์ ์ ๋ํ ์ฌํญ์ ํ์ฅ ๊ฐ๋ฅํ <details>
ํ๊ทธ๋ก ํ์ธ ๊ฐ๋ฅํฉ๋๋ค.
- ๋ฆฌํํ ๋ง ๋ณด์กฐ https://marketplace.visualstudio.com/items?itemName=paulshen.paul-typescript-toolkit
- R+TS Code Snippets (์ฌ๋ฌ๊ฐ์ง ํ์ฅ ํ๋ก๊ทธ๋จ์ด ์์ต๋๋ค...)
- TypeScript ๊ณต์ ํ์ฅํ๋ก๊ทธ๋จ https://code.visualstudio.com/docs/languages/typescript
Cloud setups:
- TypeScript Playground with React๋ ์ฝ๋๋ฅผ ์คํํ์ง ์๊ณ Types๋ฅผ ๋๋ฒ๊น ๋ง ํ๋ ๊ฒฝ์ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- CodeSandbox - cloud IDE, ๋งค์ฐ ๋น ๋ฅธ ๋ถํ ์๋๋ฅผ ๊ฐ์ง๋๋ค.
- Stackblitz - cloud IDE, ๋งค์ฐ ๋น ๋ฅธ ๋ถํ ์๋๋ฅผ ๊ฐ์ง๋๋ค.
Local dev setups:
- Next.js:
npx create-next-app -e with-typescript
๋ช ๋ น์ด๋ ์๋ก์ด NextJS ํ๋ก์ ํธ๋ฅผ ํ์ฌ ํด๋์ ์์ฑํฉ๋๋ค. - Create React App:
npx create-react-app name-of-app --template typescript
๋ช ๋ น์ด๋ ์๋ก์ด NextJS ํ๋ก์ ํธ๋ฅผ ์๋ก์ด ํด๋์ ์์ฑํฉ๋๋ค. - Vite:
npm create vite@latest my-react-ts-app -- --template react-ts
- Meteor:
meteor create --typescript name-of-my-new-typescript-app
- Ignite for React Native:
ignite new myapp
- TSDX:
npx tsdx create mylib
๋ช ๋ น์ด๋ React+TS ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฅผ ์์ฑํฉ๋๋ค. (in future: TurboRepo)
๋ค๋ฅธ ๋๊ตฌ๋ค
์์ง ๋ณด์์ด ํ์ํ์ง๋ง ํ์ธํด ๋ณผ ๋งํ ๊ฐ์น๊ฐ ์๋ ๋๊ตฌ๋ค:
- Snowpack:
npx create-snowpack-app my-app --template app-template-react-typescript
- Docusaurus v2 with TypeScript Support
- Parcel
- JP Morgan's
modular
: CRA + TS + Yarn Workspaces toolkit.yarn create modular-react-app <project-name>
Manual setup:
- Basarat's guide๋ React + TypeScript + Webpack + Babel ์ ์๋์ผ๋ก ์ค์ ํ ๊ฒฝ์ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ํนํ,
@types/react
์@types/react-dom
๊ฐ ์ค์น๋์ด ์๋์ง ํ์ธ์ด ํ์ํฉ๋๋ค. (์ต์ํ์ง ์์ ๋ด์ฉ์ด๋ผ๋ฉด DefinitelyTyped project ์ ๋ํด ๋ ์์๋ณด์ธ์.) - ๋ํ ๋ง์ React + TypeScript bolierplates๋ค์ด ์์ต๋๋ค. ์ฐ๋ฆฌ์ ๋ค๋ฅธ ๋ฆฌ์์ค ๋ฆฌ์คํธ๋ฅผ ํ์ธํด์ฃผ์ธ์.
์๋์ 7๋ถ๋ก ๊ตฌ์ฑ๋ "React Typescript Course" ๋น๋์ค ์๋ฆฌ์ฆ๋ฅผ ํตํด TypeScript with React์ ๋ํ ์๊ฐ๋ฅผ ๋ค์ ์ ์์ต๋๋ค.
ํจ์ ์ปดํฌ๋ํธ๋ props
๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ๊ณ JSX element๋ฅผ ๋ฐํํ๋ ์ผ๋ฐ์ ์ธ ํจ์๋ก ์์ฑ๋ ์ ์์ต๋๋ค.
// props์ ํ์
์ ์ - ๋ ๋ง์ ์์๋ "์ปดํฌ๋ํธ Props ํ์ดํ"์์ ํ์ธํ ์ ์์ต๋๋ค.
type AppProps = {
message: string;
}; /* export ํ๋ค๋ฉด consumer๊ฐ extendํ ์ ์๋๋ก `interface`๋ฅผ ์ฌ์ฉํ์ธ์. */
// ํจ์ ์ปดํฌ๋ํธ๋ฅผ ์ ์ํ ์ ์๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ; return type์ ์ถ๋ก ๋ฉ๋๋ค.
const App = ({ message }: AppProps) => <div>{message}</div>;
// ์ค์๋ก ๋ค๋ฅธ ํ์
์ ๋ฐํํ์์ ๋ ์๋ฌ๊ฐ raise ๋๋๋ก return type์ ๋ช
์ํ ์ ์์ต๋๋ค.
const App = ({ message }: AppProps): JSX.Element => <div>{message}</div>;
// type ์ ์ธ์ ํจ์ ์ปดํฌ๋ํธ ์ ์ธ์ ํฌํจ์ํฌ ์ ์์ต๋๋ค.;์ด ๋ฐฉ๋ฒ์ prop types์ ์ด๋ฆ์ ๋ถ์ด์ง ์์๋ ๋์ง๋ง ์ฝ๋๊ฐ ๋ฐ๋ณต๋ฉ๋๋ค.
const App = ({ message }: { message: string }) => <div>{message}</div>;
Tip: type destructure ์ ์ธ์ ์ํด Paul Shen's VS Code Extension๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. (keyboard shortcut์ ์ถ๊ฐ ํ์ธ์.)
React.FC
๊ฐ ๊ถ์ฅ๋์ง ์๋ ์ด์ ๋ ๋ฌด์์ผ๊น์? React.FunctionComponent
/React.VoidFunctionComponent
๋ ์ด๋ค๊ฐ์?
React+TypeScript codebases์์ ๋ค์ ๋ณด์์ ์ ์์ต๋๋ค.
const App: React.FunctionComponent<{ message: string }> = ({ message }) => <div>{message}</div>;
ํ์ง๋ง, ํ์ฌ React.FunctionComponent
(๋๋ ๊ฐ๋ตํ๊ฒ ์จ์ React.FC
)๋ ๊ถ์ฅ๋์ง ์๋๋ค๋ ๊ฒ์ ๋๋ถ๋ถ์ ์ฌ๋๋ค์ด ๋์ํฉ๋๋ค. ๋ฌผ๋ก ์ด ์ฃผ์ ์ ๋ํ ๋ฏธ๋ฌํ ์๊ฒฌ ์ฐจ์ด๊ฐ ์์ ์๋ ์์ง๋ง, ๋ง์ฝ ์ด ์๊ฒฌ์ ๋์ํ๊ณ React.FC
๋ฅผ ๋น์ ์ ์ฝ๋๋ฒ ์ด์ค์์ ์ ๊ฑฐํ๊ณ ์ถ๋ค๋ฉด, ์ด jscodeshift codemond๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
"์ผ๋ฐ์ ์ธ ํจ์" ๋ฒ์ ๊ณผ์ ์ฐจ์ด์ ๋ค์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
-
React.FunctionComponent
๋ return type์ ๋ช ์์ ์ผ๋ก ๋ฐํ๋๋ค. ํ์ง๋ง ์ผ๋ฐ์ ์ธ ํจ์ ๋ฒ์ ์ ์์์ ์ ๋๋ค(๋๋ ์ถ๊ฐ์ ์ธ ์ด๋ ธํ ์ด์ (annotation)์ด ํ์ํฉ๋๋ค). -
displayName
,propTypes
, ๊ทธ๋ฆฌ๊ณdefaultProps
์ ๊ฐ์ static properties๋ฅผ ์ํ ์๋์์ฑ(autocomplete)๊ณผ ํ์ ์ฒดํฌ(Typechecking)๋ฅผ ์ง์ํฉ๋๋ค.React.FunctionComponent
์ ํจ๊ปdefaultProps
์ ์ฌ์ฉํ๋๋ฐ ๋ช ๊ฐ์ง ์๋ ค์ง ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ๋ฌธ์ ์ ๋ํ ์์ธํ ๋ด์ฉ์ ํ์ธํ์ธ์. ์ฐ๋ฆฌ๋ ๊ฐ๋ฐ์๋์ด ์ฐพ์๋ณผ ์ ์๋ ๋ณ๊ฐ์defaultProps
์น์ ์ ์ ๊ณตํ๊ณ ์์ต๋๋ค.
-
React 18 type ์ ๋ฐ์ดํธ ์ด์ ์๋,
React.FunctionComponent
์ดchildren
์ ๋ํ ์์์ ์ธ ์ ์(implicit definition)๋ฅผ ์ ๊ณตํ์์ต๋๋ค. ์ด๊ฒ์ ์ด๋ค ํ ๋ก ๊ณผ์ ์ ๊ฑฐ์ณค๊ณ ๊ฒฐ๊ณผ์ ์ผ๋กReact.FC
๊ฐ Create React App TypeScript template์์ ์ ๊ฑฐ๋ ์ด์ ์ค ํ๋๊ฐ ๋์์ต๋๋ค.
// React 18 types ์ด์
const Title: React.FunctionComponent<{ title: string }> = ({ children, title }) => (
<div title={title}>{children}</div>
);
(Deprecated)React.VoidFunctionComponent
๋๋ React.VFC
์ฌ์ฉํ๊ธฐ
@types/react 16.9.48์์, React.VoidFunctionComponent
๋๋ React.VFC
type์ children
์ ๋ช
์์ ์ผ๋ก ํ์ดํ(typing) ํ๊ธฐ ์ํด ์ถ๊ฐ๋์์ต๋๋ค.
ํ์ง๋ง, React.VFC
์ React.VoidFunctionComponent
๋ React 18 (https://github.com/DefinitelyTyped/DefinitelyTyped/pull/59882)์์ ๋์ด์ ์ฌ์ฉ๋์ง ์๊ฒ ๋์์ต๋๋ค(deprecated). ๋ฐ๋ผ์ ์ด ์์๋ฐฉํธ์ React 18+ ์์ ๋์ด์ ๊ถ์ฅ๋์ง ์์ต๋๋ค.
์ผ๋ฐ์ ์ธ ํจ์ ์ปดํฌ๋ํธ๋ React.FC
๋ฅผ ์ฌ์ฉํด ์ฃผ์ธ์.
type Props = { foo: string };
// ์ง๊ธ์ ๊ด์ฐฎ์ง๋ง, ๋ฏธ๋์๋ ์๋ฌ๋ฅผ ๋ฐ์์ํฌ ๊ฒ์
๋๋ค.
const FunctionComponent: React.FunctionComponent<Props> = ({ foo, children }: Props) => {
return (
<div>
{foo} {children}
</div>
); // OK
};
// ์ง๊ธ์ ์๋ฌ๋ฅผ ๋ฐ์์ํค๊ณ , ๋ฏธ๋์๋ ๋์ด์ ์ฌ์ฉ๋์ง ์์๊ฒ์
๋๋ค.(Deprecated)
const VoidFunctionComponent: React.VoidFunctionComponent<Props> = ({ foo, children }) => {
return (
<div>
{foo}
{children}
</div>
);
};
- ๋ฏธ๋์๋, props๋ฅผ ์๋์ผ๋ก
readonly
๋ผ๊ณ ํ์ํ ์๋ ์์ต๋๋ค. ํ์ง๋ง, props ๊ฐ์ฒด๊ฐ ํ๋ผ๋ฏธํฐ ๋ฆฌ์คํธ์์ destructure ๋๋ค๋ฉด, ์ด๊ฒ์ ์๋ฏธ์๋ ํ๋ ์ ๋๋ค.
๋๋ถ๋ถ์ ๊ฒฝ์ฐ์๋ ์ด๋ค syntax๋ฅผ ์ฌ์ฉํ๋์ง ํฐ ์ฐจ์ด๊ฐ ์์ง๋ง, React.FunctionComponent
์ ๋ณด๋ค ๋ช
์์ ์ธ ํน์ฑ์ ์ ํธํ๋ ๊ฒ์ด ์ข์๊ฒ์
๋๋ค.
์ฃผ์ํด์ผ ํ ์ฌํญ
๋ค์์ ํจํด์ ์ง์๋์ง ์์ต๋๋ค. :
์กฐ๊ฑด๋ถ ๋ ๋๋ง(conditional rendering)
const MyConditionalComponent = ({ shouldRender = false }) => (shouldRender ? <div /> : false); // JS ์์๋ ์ด๋ ๊ฒ ํ์ง ๋ง์ญ์์ค.
const el = <MyConditionalComponent />; // ์๋ฌ๋ฅผ throw ํฉ๋๋ค.
์ด ํจํด์ด ์ง์๋์ง ์๋ ์ด์ ๋ ์ปดํ์ผ๋ฌ์ ํ๊ณ ๋๋ฌธ์
๋๋ค. ํจ์ ์ปดํฌ๋ํธ๋ JSX expression ๋๋ null
์ด์ธ์ ๋ค๋ฅธ ์ด๋ค ๊ฒ๋ ๋ฐํํ ์ ์์ต๋๋ค. ๋ฐํํ ์ ์๋ ๊ฒ์ด ๋ฐํ๋๋ค๋ฉด ํด๋น ํ์
์ Element
์ ํ ๋น๋ ์ ์๋ค๋ ์๋ฌ ๋ฉ์ธ์ง๋ฅผ ๋ณด๊ฒ๋ ๊ฒ์
๋๋ค. ("{the other type} is not assignable to Element
.")
Array.fill
const MyArrayComponent = () => Array(5).fill(<div />);
const el2 = <MyArrayComponent />; // throws an error
์์ฝ๊ฒ๋ ํจ์์ ํ์ ์ annotate ํ๋ ๊ฒ์ ์๋ฌด๋ฐ ๋์์ด ๋์ง ์์๊ฒ์ ๋๋ค. React๊ฐ ์ง์ํ๋ ๋ค๋ฅธ ํน๋ณํ ํ์ (exotic type)์ ๋ฐํํ๊ณ ์ ํ๋ค๋ฉด ํ์ ํ๋ช (type assertion)์ ์ํํด์ผ ํฉ๋๋ค. :
const MyArrayComponent = () => Array(5).fill(<div />) as any as JSX.Element;