Styled-components Typescript 적용하기 (+Media query)

시작하기

기존에 styled-components 반응형 및 스타일 리셋 설정하기 포스트을 통해서 스타일 최초 설정해보았습니다.

theme를 입력했을때 typescript로 자동으로 연결해주는 부분이 미흡했습니다. 타입스크립트를 styled-components 와 제대로 사용해보도록 하겠습니다.

설치하기

1
npm i styled-components && npm i -D @types/styled-components

styled components를 설치해줍니다.

초기설정

테마설정

테마로 사용할 폰트, 색상, 레이아웃 등을 선언해줍니다.

src/styles/theme.ts
1
2
3
4
5
6
7
8
9
10
const color = {
white: "white",
black: "black",
};

export const theme = {
color,
};

export type Theme = typeof theme;

테마를 불러올수 있게 ThemeProvider로 App을 감싸줍니다.

1
2
3
4
5
6
7
8
import { theme } from './styles/theme.ts';
import { ThemeProvider } from 'styled-components';

//...
<ThemeProvider theme={theme}>
<App/>
</ThemeProvider>
//...

타입정의 이전

이것만으로 테마를 사용할수는 있습니다만, 타입스크립트를 제대로 사용하기 위해서는 styled.d.ts를 입력해주어야합니다. styled.d.ts를 정의 해주면 다음과 같습니다.

타입정의 이후

자동완성이나 어떤값이 들어가는지 미리 확인할 수 있기때문에 더욱 styled-components를 사용하기 쉬워집니다.

styled.d.ts

정의하는 방법은 정말로 간단합니다.

src/typing/styled.d.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Theme } from "../styles/theme";
import { CSSProp } from "styled-components";

declare module "styled-components" {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface DefaultTheme extends Theme {}
}

declare module "react" {
interface Attributes {
css?: CSSProp | CSSObject;
}
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface 이 부분은 린트에서 에러가 날때 타입이 {} 빈값으로 되어있는 룰을 무시해주는 역할을 합니다.

declare modlue "react"~~~는 코드를 다음과 같이 쉽게 사용하기 위해 초기 설정을 해준것 입니다.

1
2
3
4
5
6
7
8
9
import styled from "styled-components/macro";

<div
css={`
border: 1px solid red;
`}
>
Test
</div>;

styled.d.ts파일에서 정의해주는 역할을 합니다.

Media query 반응형

타입정의를 하고 나면 styled-components 반응형 및 스타일 리셋 설정하기 포스트에서 사용한 코드에서 에러가 나는 것을 확인할수 있습니다.

에러

기존에 작성했던 코드를 수정 혹은 새로 작성하겠습니다.

src/styles/media.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import { CSSProp, css } from "styled-components";

type MediaQueryProps = {
mobile: number;
tablet: number;
desktop: number;
};

const sizes: MediaQueryProps = {
mobile: 580,
tablet: 768,
desktop: 1284,
};

// // Iterate through the sizes and create a media template
type BackQuoteArgs = string[];

const media = {
mobile: (literals: TemplateStringsArray, ...args: BackQuoteArgs): CSSProp =>
css`
@media only screen and (max-width: ${sizes.mobile}px) {
${css(literals, ...args)}
}
`,
tablet: (literals: TemplateStringsArray, ...args: BackQuoteArgs): CSSProp =>
css`
@media only screen and (max-width: ${sizes.tablet}px) {
${css(literals, ...args)}
}
`,
desktop: (literals: TemplateStringsArray, ...args: BackQuoteArgs): CSSProp =>
css`
@media only screen and (max-width: ${sizes.desktop}px) {
${css(literals, ...args)}
}
`,
} as Record<
keyof typeof sizes,
(l: TemplateStringsArray, ...p: BackQuoteArgs) => CSSProp
>;

export default media;

이후 테마에 연결을 해주도록 합니다.

src/styles/theme.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import media from "./media";

const color = {
white: "white",
black: "black",
};

export const theme = {
color,
media,
};

export type Theme = typeof theme;

이후 사용해보면 정상적으로 작동하는 것을 알 수 있습니다.

결과

회고

styled-components에 styled.d.ts를 적용하면 media적용시에 TemplateStringsArray 부분이 에러가 발생했는데 검색으로도 해결하기 힘든 문제였습니다. 구글 검색과 새 프로젝트를 만들어 하나하나 분석해가면서 해보니 해결할 수 있었습니다.

Share