LoginSignup
20
8

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-08-30

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

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

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

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

20
8
1

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