타입스크립트는 자바스크립트의 확장판
에러 방지와 자동완성(생산성 향상)의 이점을 가진다.
아직 협업 경험이 없는데, 협업에서의 문제를 줄여줄 수 있다고 하더라!
function App() {
return (
<div>
<Box bgColor="blue" />
<Box bgColor="red" />
</div>
);
}
파란 네모와 빨간 네모를 그리고 싶어서 Box 컴포넌트에 각각 색을 넘겨주었다.
Box에서 bgColor을 받아보자.
function Box({bgColor}) {
return <Container />;
}
bgColor라는 prop을 받고싶은데... 타입스크립트 환경에서는 에러가 발생한다.
bgColor의 타입이 지정되지 않았기 때문이다.
우리는 interface를 사용해서 Box 컴포넌트가 받을 props의 타입을 지정해줄 수 있다.
interface BoxProps {
bgColor: string;
}
function Box({bgColor}: BoxProps) {
return <Container />;
}
이렇게 BoxProps라는 interface를 통해 Box가 받는 props의 타입을 지정해주면 자동완성도 되고 아주 편해진다. 하하
이제 Box에서 Container로 bgColor를 넘겨주자.
function Box({bgColor}: CircleProps) {
return <Container bgColor={bgColor} />;
}
const Container = styled.div`
width: 100px;
heifht: 100px;
background-color: ${(props) => props.bgColor}
`
이렇게 쓰면 될 것 같지만 안된다.
Container 컴포넌트에서 bgColor를 사용하려면 또 타입을 지정해줘야한다.
마찬가지로 interface를 사용하자.
interface ContainerProps {
bgColor: string;
}
const Container = styled.div<ContainerProps>`
width: 100px;
height: 100px;
background-color: ${(props) => props.bgColor}
`
완성!
합치면 이렇게 된다.
interface ContainerProps {
bgColor: string;
}
const Container = styled.div<ContainerProps>`
width: 100px;
height: 100px;
background-color: ${(props) => props.bgColor}
`
interface BoxProps {
bgColor: string;
}
function Box({bgColor}: BoxProps) {
return <Container bgColor={bgColor}/>;
}
이렇게 interface를 사용해서 props를 전달할 수 있다.
optional props
interface를 사용하면서 이런 생각이 들 수 있다.
'박스 두개 중에 한개만 테두리를 넣고 싶은데, borderColor를 양쪽에 다 넘겨줘야지만 에러가 안나네?'
그러니까... 특정 props는 필수가 아니라 선택으로 넣고 싶을 수도 있지 않나?
function App() {
return (
<div>
<Box bgColor="blue" />
<Box bgColor="red" borderColor="green" />
</div>
);
}
interface BoxProps {
bgColor: string;
borderColor: string;
}
function Box({bgColor, borderColor}: BoxProps) {
return <Container bgColor={bgColor} borderColor={borderColor} />;
}
이렇게 아까 bgColor때와 동일하게 하면 에러가 발생한다.
파란 박스에는 borderColor가 없기 때문.
borderColor를 필수가 아닌 선택으로 하고싶다면 ?를 사용하자.
interface BoxProps {
bgColor: string;
borderColor?: string;
}
?하나면 선택이 된다.
그리고 a ?? b를 사용하면 '있으면 a를, 없으면 b를'이라는 표현도 가능하다.
function Box({bgColor, borderColor}: BoxProps) {
return <Container
bgColor={bgColor}
borderColor={borderColor ?? bgColor}
//borderColor가 있으면 borderColor를 사용하고, 없으면 bgColor를 사용해라
/>;
}
혹 prop에 기본값을 설정하고 싶다면 아래와 같이 사용하면 된다.
interface BoxProps {
bgColor: string;
borderColor?: string;
}
function Box({bgColor, borderColor="red"}: BoxProps) {
return <Container
bgColor={bgColor}
borderColor={borderColor}
/>;
}
이제 borderColor는 기본값이 red다.
만약 borderColor를 지정해주지 않는다면, 자동으로 빨간색이 된다.
const [state, setState] = useState(1);
//초기값으로 1을 넣으면 자동으로 state의 타입이 number이 된다.
//즉, 초기값의 타입이 state의 타입이 된다.
초기값의 타입과 다른 값이 들어갈 일은 잘 없겠지만...
혹시나 state에 들어갈 값이 한 타입이 아니라면?
const [state, setState] = useState<string | number>(0);
setState(2);
setState("hi");
이렇게하면 state에 string과 number 두 타입 모두 들어갈 수 있게 된다.
function App() {
const [username, setUsername] = useState("");
//username에 유저가 입력한 값이 들어옴
const onChange = (event: React.FormEvent<HTMLInputElement>) => {
const {
currentTarget: { value },
} = event;
//구조분해할당. event.currentTarget.value랑 같은 말
setUsername(value);
};
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(`hi ${username}`);
};
return (
<div>
<form onSubmit={onSubmit}>
<input
value={username}
onChange={onChange}
placeholder="id"
type="text"
></input>
<button>log in</button>
</form>
</div>
);
}
먼저, styled.d.ts를 생성한다.
import "styled-components";
declare module "styled-components" {
export interface DefaultTheme {
textColor: string;
bgColor: string;
}
}
그리고 theme.ts를 생성해서 dark/light theme를 만든다.
import { DefaultTheme } from "styled-components";
export const darkTheme: DefaultTheme = {
textColor: "white",
bgColor: "black",
};
export const lightTheme: DefaultTheme = {
textColor: "black",
bgColor: "white",
};
index.tsx에서 ThemeProvider 설정하기
import { darkTheme, lightTheme } from "./theme";
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<React.StrictMode>
<App />
<ThemeProvider theme={lightTheme}>
<App />
</ThemeProvider>
</React.StrictMode>
);