이미 styled component를 사용해 화면 테마를 설정한 경험이 있기 때문에 emotion도 쉽게 설정할 수 있을 줄 알았다. 실제로 찾아본 theme 적용방법도 완전히 동일했기 때문에 냉큼 시도해봤다.
const App = () => {
return (
<ThemeProvider theme={theme}>
<Home />
</ThemeProvider>
);
};
이렇게 루트 컴포넌트를 ThemeProvider로 감싸고 사용할 theme을 주기만 하면 emotion으로 스타일 컴포넌트를 만들 때 props를 통해 theme에 접근할 수 있게 된다.
const StyleComponent = styled.div`
background-color: ${props => props.theme.colors.background}
`;
여기까지는 아무 문제가 없었다.
typescript를 사용할 때는 props에 사용할 타입을 선언하는 과정이 동반되어야한다. 때문에 내가 사용할 타입을 미리 선언해서 사용하기로 했다.
export interface StylePropTypes {
theme: {
colors: Record<keyof typeof theme.colors, string>;
};
...
}
const StyleComponent = styled.div`
background-color: ${(props:Pick<StylePropTypes,'theme'>) => props.theme.colors.background}
`;
//또는
const StyleComponent = styled.div<Pick<StylePropTypes,'theme'>>`
background-color: ${(props) => props.theme.colors.background}
`;
그런데 이런 에러를 만났다.
간략하게 해석해보면 theme이 필요한데 누락되어 있다는 얘기였다. 실제로 StyleComponent를 사용할 때는 theme을 prop으로 줄 필요가 없다. 이미 루트 컴포넌트에서 ThemeProvider로 theme을 주고 있기 때문에, 굳이 StyleComponent를 사용할 때 theme을 prop으로 넘겨주지 않아도 스타일 컴포넌트 선언 시점에 props.theme 형태로 접근이 가능하기 때문이다.
const Home = () => {
return <StyleComponent> // <StyleComponent theme={theme}> 이렇게 할 필요가 없다.
...
</StyleComponent>
}
하지만 타입스크립트는 이 사실을 알지 못하는지 왜 theme을 사용할거면서 prop으로 넘기지 않고 있냐고 에러를 내고 있는 것이다.
찾아보니 emotion에서 theme을 사용하기 위해서는 emotion.d.ts라는 별도의 type 정의 파일을 만들어야 했다. 가이드를 따라 아래와 같이 작성하니 에러가 사라졌다.
// src/styles/emotion.d.ts
import '@emotion/react'
import {theme} from './theme'
type ThemeTpye = typeof theme
declare module '@emotion/react' {
export interface Theme extends ThemeTpye {}
}
참고 링크 2: https://velog.io/@yeogenius/React-Emotion.js-%EB%A1%9C-Theme-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0