8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

(小ネタ) emotion (emotion-js) + TypeScript で型安全にテーマ付きの styled.** を使いたくなったら

Last updated at Posted at 2019-11-26

解決したいこと

下記のような、自前のテーマを持っていたとして、

export type OurTheme = {
  ourSuperAwesomeColor: string
}

emotionで、下記のようなstyled-componentなコードを書きたい場合、型エラーでコンパイルが通りません。

// TypeScript「 `({theme})` の型がわかりましぇ〜ん!」
const AwesomeHeading = styled.h1`
  color: ${ ({theme}) => theme.ourSuperAwesomeColor };
`

さて、どうすればいいでしょうか。

キャストは嫌だ

もちろん、下記のようなダサいことをすれば通るんですが、コードのそこかしこに同じような ゴミ キャストを撒き散らすと考えると微妙です。

const AwesomeHeading = styled.h1`
  color: ${ ({theme}) => (theme as OurTheme).ourSuperAwesomeColor };
`

あなた知らないの? styled.** は実は省略可能な型変数を持っていて、省略されている型変数の2番目をきちんと指定すればテーマの型を指定できるよ?

なるほど…??

const AwesomeHeading = styled.h1<ここに入れる型がわからない, OurTheme>`
  color: ${ ({theme}) => theme.ourSuperAwesomeColor };
`

ここに入れる型がわからない の型変数(本来はpropsの型を示すところでした)の記載を省略したいのですが、TypeScriptでは残念なことに今のところは省略可能な任意の位置の型変数を省略したままにする術がありません。

あー困った困った…

(ちなみに型がわからないからといって any とか入れると、一気に型チェック無しの世界に入るので、やめたほうがいいです。)

仕方ないので、自前で styled を用意する

ということで、私は自前で styled を用意することにしました。

// `@emotion/styled-base` から import しないように注意
import styled, { CreateStyled } from "@emotion/styled";

// 既存の `styled` をそのまま別の型として見るだけの変数を宣言。
export const ourStyled: CreateStyled<OurTheme> = styled;

上記のようなものを用意しておくと、下記のように書けます。

const AwesomeHeading = ourStyled.h1`
  color: ${ ({theme}) => theme.ourSuperAwesomeColor };
`

これでスッキリ!

8
3
5

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
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?