LoginSignup
8

posted at

updated at

Next.js (TypeScript) で MUI (Material UI) を型安全に使用する

MUIの公式サイトには 様々なフレームワークでの Example が掲載されております。
その中にはもちろん Next.js (TypeScript) でのExample も掲載されています。
基本的にはそのExampleのとおりにやれば、MUIを導入できるのですが…

そのExampleが、色々とツッコミどころがあるのです。
例えば、 any 使いまくるのは TypeScript的にどうなの?

というわけで、Exampleの微妙なところを徹底的に直してみましたので、ぜひ参考にしていただければうれしいです。
ではいきましょう!

前提条件

ライブラリのバージョン

Next.js  12.2.4
MUI      5.10.1

リポジトリはこちら

今回のリポジトリをこちらに公開しておきます。
ぜひ参考にしてみてください。

any を撲滅する

公式Exampleの _document.tsx には、 any が結構使われています。たとえば

_document.tsx
export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        {/* 略 */}
        {(this.props as any).emotionStyleTags}
        {/* 略 */}
      </Html>
    );
  }
}

this.props as any と書いてありますね。
これは props の中に emotionStyleTags が定義されていないから、無理やり any に変換しているわけで、
根本的に解決するなら、 emotionStyleTags を定義すればOKです。こんな感じで↓

_document.tsx
+ type MyDocumentProps = {
+   emotionStyleTags: EmotionJSX.Element[]
+ }
+ 
- export default class MyDocument extends Document {
+ export default class MyDocument extends Document<MyDocumentProps> {
    render() {
      return (
        <Html lang="en">
          {/* 略 */}
-         {(this.props as any).emotionStyleTags}
+         {this.props.emotionStyleTags}
          {/* 略 */}
        </Html>
      );
    }
  }

他にも any が使われている箇所があるので、型を調べて、どんどん潰していきます。
詳しくは、修正した後のコードをご覧ください。

let を撲滅する

公式Exampleの createEmotionCache.ts の変数定義に let が使われています。

createEmotionCache.ts
import createCache from '@emotion/cache';

const isBrowser = typeof document !== 'undefined';

// On the client side, Create a meta tag at the top of the <head> and set it as insertionPoint.
// This assures that MUI styles are loaded first.
// It allows developers to easily override MUI styles with other styling solutions, like CSS modules.
export default function createEmotionCache() {
  let insertionPoint;

  if (isBrowser) {
    const emotionInsertionPoint = document.querySelector<HTMLMetaElement>(
      'meta[name="emotion-insertion-point"]',
    );
    insertionPoint = emotionInsertionPoint ?? undefined;
  }

  return createCache({ key: 'mui-style', insertionPoint });
}

let insertionPoint; と書いてありますね。
もちろん、 let は完全な悪ではありませんが、使わずにすむのであればそうしたいものです。
(参考: JavaScriptからletを絶滅させ、constのみにするためのレシピ集

というわけで、 let をなくし、 const を使えるようリファクタリングしてみました↓

createEmotionCache.ts
import createCache from "@emotion/cache"
import type { EmotionCache } from "@emotion/cache"

// On the client side, Create a meta tag at the top of the <head> and set it as insertionPoint.
// This assures that MUI styles are loaded first.
// It allows developers to easily override MUI styles with other styling solutions, like CSS modules.
const getInsertionPoint = (): HTMLMetaElement | undefined => {
  if (typeof document !== "undefined") {
    const insertionPoint = document.querySelector<HTMLMetaElement>(
      'meta[name="emotion-insertion-point"]'
    )
    if (insertionPoint != null) {
      return insertionPoint
    }
  }
}

const createEmotionCache = (): EmotionCache => {
  return createCache({ key: "mui-style", insertionPoint: getInsertionPoint() })
}

export default createEmotionCache

(ちなみに、 function よりもアロー関数の方が好きなので、ついでに変えています)
修正した後のソースコードはこちらからご覧いただけます。

まとめ

MUI公式のExampleは、もちろんそのまま動きますし、そのまま使うのが悪いとは思いません。
とはいえ、こういう公式サイトに載っているソースコードを、思考停止でそのまま使うのではなく、

なぜそういう書き方をするのか、本当にこの書き方でいいのか

など考えられるようになると、エンジニアとして成長できるのではないかと思います。

というわけで、しっかりと思考を巡らせていきましょう!

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
What you can do with signing up
8