ES6でクラス名を動的に変更する方法

ES7のdecoratorsでクラスを生成するとクラス名がそのデコレータのものになってしまいます。
例えば:

import React from 'react'

function addAwesomeProperty (Spec, Component = Spec) {
  class AwesomeClass extends React.Component {
    render () {
      return React.createElement(
        Component,
        Object.assign({ awesome: 'yes!' }, this.props)
      )
    }
  }
  return AwesomeClass
}

@addAwesomeProperty
class OriginalClass extends React.Component {
  ...
}

こうすると生成後のクラスの名前は AwesomeClass になってしまいます。これは不便。
だからといってクラス名を以下のように変えようとしても出来ません:

AwesomeClass.name = 'OriginalClass'

なぜなら name プロパティは writable ではないからです:

Object.getOwnPropertyDescriptor(AwesomeClass, 'name')
    { value: 'func',
      writable: false,
      enumerable: false,
      configurable: true }

しかしES6の仕様によると以下の方法で変更できるとの記述を見つけました:

> Object.defineProperty(func, 'name', {value: 'foo', configurable: true});
> func.name
  'foo'

という事は、前述の例を以下のように修正すればクラス名に影響を与えずに済みます:

import React from 'react'

function addAwesomeProperty (Spec, Component = Spec) {
  class AwesomeClass extends React.Component {
    render () {
      return React.createElement(
        Component,
        Object.assign({ awesome: 'yes!' }, this.props)
      )
    }
  }
  // 追加
  Object.defineProperty(AwesomeClass, 'name', { value: Component.name, configurable: true })

  return AwesomeClass
}

まぁ、これが設計として正しいのかは謎です。

蛇足

動的なクラス名を定義する方法として、

const classes = { [ dynamicClassName ]: class { ... } }
classes[dynamicClassName].name  // => dynamicClassName

みたいな方法もあるみたいだけど、自分の環境では常に _class となって上手く行かなかった。
自分のbabelの設定が悪いのかもしれないけど。


コメントを残す