Why Typescript?
타입스크립트는 자바스크립트에 타입을 부여한 언어로 다음 두 가지 관점에서 자바스크립트 코드를 개선하고 개발 생산성을 높일 수 있다.
- 에러의 사전 방지
- 코드 가이드 및 자동 완성
const sum = (a,b) => a+b;
위의 자바스크립트 코드는 a와 b를 입력받아 a + b의 값을 구하는 함수이지만, a와 b에 숫자가 아닌 문자열 등을 넘기더라도 오류를 띄우거나 하지 않고 심지어 존재하지 않는 프로퍼티를 읽더라도 undefined를 주고 넘어가는 등 에러의 사전 방지에 취약한 모습을 보인다.
const sum = (a:number, b:number) => a+b;
sum(1,2);
위와 같이 :를 이용하여 타입을 정의하는 방식을 Type Annotation이라고 한다. 이렇게 타입스크립트를 사용하여 인자의 타입을 지정해주면 해당 코드 실행 전에 a와 b의 타입을 검사하여 의도하지 않은 코드의 동작을 예방할 수 있다. 자바스크립트에서도 propTypes를 활용하여 타입을 검사할 수 있었지만, 이는 코드가 실행된 이후에 검사하는 방식으로 타입스크립트는 코드 실행 전에 타입을 검사하게된다. 이렇게 타입을 검사하여 문제가 없다면 평범한 자바스크립트문으로 컴파일하여 브라우저가 읽을 수 있게 된다.
또한 VSCode 등 개발 툴에서 변수의 타입을 미리 알고 있기 때문에 코드 가이드나 자동 완성 기능을 온전히 사용할 수 있어 개발 생산성이 높아진다는 장점이 있다.
리액트에 타입스크립트 설치하기
# 신규 프로젝트 생성 시 타입스크립트 사용
npx create-react-app {app-name} --template typescript
# 기존 프로젝트에 타입스크립트 사용
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
# 자바스크립트 기반 라이브러리인 경우 `@types/styled-components`와 같이 추가로 DefinitelyTyped 설치
# .js 파일은 .tsx 파일로 확장자 변경 후 개발서버 재시작
props 설정하기
const Container = styled.div``;
function Circle({bgColor}) {
return <Container />;
}
일반적인 자바스크립트 환경에서는 아무 문제 없이 넘어가겠지만 타입스크립트는 bgColor의 타입을 모르기 때문에 에러를 띄운다. 이런 경우 interface 키워드를 사용해 해당 컴포넌트의 props에 대한 타입을 정의하는 인터페이스를 만들어주어야 한다.
interface CircleProps {
bgColor: string;
}
interface ContainerProps {
bgColor: string;
}
const Container = styled.div<ContainerProps>`
width: 300px;
height: 300px;
background-color: ${(props) => props.bgColor};
border-radius: 50%;
`;
function Circle({ bgColor }: CircleProps) {
return <Container bgColor={bgColor} />;
}
Optional Props
컴포넌트에 반드시 필요하지 않은 props를 설정할 때는 물음표를 붙여주면 된다.
interface CircleProps {
bgColor: string;
borderColor?: string;
}
이렇게 선언하면 borderColor는 타입이 string | undefined가 되어 전달하지 않더라도 오류를 띄우지 않게된다.
※ nullish 병합 연산자
function Circle({ bgColor, borderColor }: CircleProps) {
return <Container bgColor={bgColor} borderColor={borderColor ?? bgColor} />;
}
a ?? b와 같이 쓰이며 a가 null 또는 undefined라면 b, 아니라면 a라는 뜻으로 사용된다. 따라서 위 코드에서 borderColor를 입력받지 않았다면 borderColor로 bgColor 값을 사용하도록 할 수 있다.
※ default props 설정
function Circle({ bgColor, borderColor, text = 'Lorem Ipsum' }: CircleProps) {
return (
<Container bgColor={bgColor} borderColor={borderColor ?? bgColor}>
{text}
</Container>
);
}
위와 같이 text = 'Lorem Ipsum'라고 설정하면 text를 입력받지 않았을 때의 기본값을 지정할 수 있다.
State
const [value, setValue] = useState(true);
타입스크립트에서는 state 초기값을 보고 타입을 유추하기 때문에 에러를 띄우지 않는다.
하지만 , state 값이 undefined나 null이 될 수 있거나, 여러 타입이 올 수 있다면 타입을 따로 지정해줄 수 있다.
const [value, setValue] = useState<number | null>(0);
Event
function App() {
const [name, setName] = useState('');
const onChange = (e) => {
setName(e.target.value);
};
return (
<form>
<input type="text" value={name} onChange={onChange} />
<button>확인</button>
</form>
);
}
위 코드는 onChange 함수에서 매개변수로 전달받는 이벤트의 타입을 명시해주지 않아 오류가 뜬다.
문서를 살펴보면 onChange는 Form Events이며 이벤트를 발생시킬 요소는 <HTMLInputElement>이다.
따라서 e 객체의 타입을 다음과 같이 지정해주어야 한다.
function App() {
const [name, setName] = useState('');
const onChange = (e: React.FormEvent<HTMLInputElement>) => {
setName(e.currentTarget.value);
};
Theme
styled component 등 자바스크립트 라이브러리는 타입이 정의되어 있지 않기 때문에 타입스크립트 환경에서 에러가 발생한다. 따라서 declaration 파일을 통해 타입스크립트에게 특정 라이브러리의 모양을 설명해주어야한다.
/* styled.d.ts */
// import original module declarations
import 'styled-components';
// and extend them!
declare module 'styled-components' {
export interface DefaultTheme {
textColor: string;
bgColor: string
}
}
styled.d.ts란 이름의 declaration 파일을 생성하고 styled component의 DefaultTheme에게 인터페이스를 지정해준다.
/* theme.ts */
import { DefaultTheme } from 'styled-components';
export const lightTheme: DefaultTheme = {
textColor: '#000',
bgColor: '#fff'
};
export const darkTheme: DefaultTheme = {
textColor: '#fff',
bgColor: '#000'
};
/* index.tsx */
//...
import { ThemeProvider } from 'styled-components';
import { darkTheme } from './theme';
ReactDOM.render(
<React.StrictMode>
<ThemeProvider theme={darkTheme}>
<App />
</ThemeProvider>
</React.StrictMode>,
document.getElementById('root')
);
'Web-Frontend > React.js' 카테고리의 다른 글
[React.js] Recoil - atom (0) | 2023.03.28 |
---|---|
[React.js] React Query (0) | 2023.03.22 |
[React.js] Styled Component (0) | 2023.03.06 |
[React.js] React Router (0) | 2023.01.24 |
[React.js] SPA vs MPA (0) | 2023.01.24 |