[Javascript] ビルトインのオブジェクトに別名を付ける場合、どうすればいいのか?

import 文では解決できないと思われるので、別ファイルに関数を定義し、読み込むのが良いでしょう。

  • builtin.js

    export default class BuiltInDate extends Date {
      constructor(any) {
        super(any);
      }
    }
  • index.js

    import BuiltInDate from "./builtin";
    const date = new BuiltInDate();

バックグラウンド

Javascript のビルトインのオブジェクトや関数はかなりたくさん用意されています。

Standard built-in objects(MDN)

それは非常に便利ではありますが、次のようなケースの場合、問題があります。

import { format } from "date-fns";

export default function Date({ dateString }) {
  return (
    <time dateTime={dateString}>
      {format(new Date(dateString), "LLLL d, yyyy")}
    </time>
  );
}

date.js : Nextjs example of CMS Contentful

これは ReactJS を使って日付を表示するコンポーネントを表現しています。ここで注目すべきは関数名がDateとして定義されており、さらに内部でビルトインのDateを呼び出そうとしています。このような関数を定義した意図は可読性にあるでしょう。日付を表すのであるから、素直にDateと表現したい。CustomeDateというような独自の命名ではなく、どのプログラマーが見ても分かる名前にしたいということのように思われます。名前を付けるということはとても難しく、意図が伝わらなかったり、後々変化してしまう可能性もあります。また長い名前にしたくないということもあります。Simple is the best、古い格言がここに光ります。

しかしながらこれを走らせると以下のようにエラーになります。

TypeError: Cannot destructure property

TypeError: Cannot destructure property `dateString` of 'undefined' or 'null'.
    at new Date (/home/cms-contentful-app/.next/server/static/development/pages/index.js:363:14)
    at new Date (/home/cms-contentful-app/.next/server/static/development/pages/index.js:374:62)
    at Date (/home/cms-contentful-app/.next/server/static/development/pages/index.js:374:62)
    at processChild (/home/cms-contentful-app/node_modules/react-dom/cjs/react-dom-server.node.development.js:3043:14)
    at resolve (/home/cms-contentful-app/node_modules/react-dom/cjs/react-dom-server.node.development.js:2960:5)
    at ReactDOMServerRenderer.render (/home/cms-contentful-app/node_modules/react-dom/cjs/react-dom-server.node.development.js:3435:22)
    at ReactDOMServerRenderer.read (/home/cms-contentful-app/node_modules/react-dom/cjs/react-dom-server.node.development.js:3373:29)
    at renderToString (/home/cms-contentful-app/node_modules/react-dom/cjs/react-dom-server.node.development.js:3988:27)
    at render (/home/cms-contentful-app/node_modules/next/dist/next-server/server/render.js:83:16)
    at Object.renderPage (/home/cms-contentful-app/node_modules/next/dist/next-server/server/render.js:419:16)
    at Function.getInitialProps (/home/cms-contentful-app/.next/server/static/development/pages/_document.js:293:19)
    at Object.loadGetInitialProps (/home/cms-contentful-app/node_modules/next/dist/next-server/lib/utils.js:59:29)
    at Object.renderToHTML (/home/cms-contentful-app/node_modules/next/dist/next-server/server/render.js:423:36)
    at process._tickCallback (internal/process/next_tick.js:68:7)

これが起きてしまうのは、ビルトインのDateを呼び出したつもりが、独自で定義したDate関数を呼び出していたからです。そのため、その独自の関数が再帰的に呼び出されて型エラーが発生しました。

Error

解決方法

別ファイルに関数を定義し、読み込むのが良いでしょう。

  • builtin.js

    export default class BuiltInDate extends Date {
      constructor(any) {
        super(any);
      }
    }
  • index.js

    import { format } from "date-fns";
    import BuiltInDate from "./builtin";
    
    export default function Date({ dateString }) {
      return (
        <time dateTime={dateString}>
          {format(new BuiltInDate(dateString), "LLLL d, yyyy")}
        </time>
      );
    }
  1. builtin.js でビルトインのDateを継承して新しいクラスを定義します。
  2. 利用したいファイルで、上記の関数を呼び出します。

この方法で期待通りに動作しますが、残念ながらファイルが増えてしまいますね。 できれば以下のように、できればいいのですが、方法は今のところ見つかりませんでした。

import { Date as BuiltInDate } from "builtin";

それでは!

Updated at: Thu Jun 25 2020

© 2020-presentTerms|Privacy