LoginSignup
73
44

More than 3 years have passed since last update.

styled-components の theme、使っていますか?styled-components には、ThemeProviderという、装飾などに関する規定値を提供する仕組みがあります。この様な構成になっているとします(通常 ThemeProvider は SPA ルーティングの上あたりに位置しますが、説明のため簡易な構成としています)

const Component: React.FC = () => (
  <ThemeProvider theme={theme}>
    <RedButton>RedButton</RedButton>
    <GreenButton>GreenButton</GreenButton>
    <BlueButton>BlueButton</BlueButton>
  </ThemeProvider>
)

ThemeProvider に渡している theme は次の様なものです。

export const theme = {
  colors: {
    red: '#f00',
    green: '#0f0',
    blue: '#00f'
  },
  layout: {
    width: 960
  }
} as const

theme は、styled-components コンストラクタ(styled(...)) にラップされた Component props に注入され、Template リテラルから参照するのが通常です。次の例は、Generics どころか型情報もありません。それにも関わらず、この参照props.theme.colors.blueにはキッチリ型推論が効いています。いったいどこから提供されたものでしょうか?

BlueButton.tsx
const StyledComponent = styled(Component)`
  background-color: ${props => props.theme.colors.blue}; /* (property) blue: "#00f" */
`

DefaultTheme 型を宣言結合拡張する

@types/styled-components を確認しましょう(v4.4.2)。DefaultThemeという型定義があります。これは先日の投稿と同じ仕組みを使った、型定義の注入テクニックです。DefaultTheme として用意された空っぽの interface に対し、宣言結合拡張することで、プロジェクト固有の型定義を注入することが出来ます。

import 'styled-components'
// ______________________________________________________
//
export const theme = {
  colors: {
    red: '#f00',
    green: '#0f0',
    blue: '#00f'
  },
  layout: {
    width: 960
  }
} as const
// ______________________________________________________
//
type AppTheme = typeof theme
// ______________________________________________________
//
declare module 'styled-components' {
  interface DefaultTheme extends AppTheme {}
}

今のところ私は遭遇したことがありませんが、ThemeProvider が複数ある場合は、この手法は使えません。ここで紹介した内容は以下のリポジトリで確認できます。

73
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
73
44