🚀

[Typescript] Classの型からインスタンスの型を推論させる方法

2022/11/22に公開

結論

class A {
  static id: 'A';
}

type InstanceOf<ClassType extends {new (...args: any[]): any; prototype: any;}> = ClassType['prototype']

type X = InstanceOf<typeof A>
// X => Aのインスタンス型

何に使えるか

pluginなどをclass形式で渡す時に使える。以下のコードはPluginによって、本来のライブラリに存在しないメソッドをプラグインのIDにインスタンスを設定することで機能を拡張する例。

type IPlugin<PluginId extends string, PluginType = any> = {
  id: PluginId
  new (a: any): PluginType
  prototype: PluginType
}

type Lib = {
  orgMethods: ()=> void
}

function someLib<Plugins extends IPlugin<any,any>[]>(args: any, options:{
  plugins?: Plugins
}): Lib & {
  [index in Extract<keyof Plugins,number>]: {
    [key in Plugins[index]['id']]: InstanceOf<Plugins[index]>
  }
}[number] {
  const exInstances = options?.plugins?.reduce((current, pluginClass) => {
    return {
      ...current,
      [pluginClass.id]: new pluginClass(args),
    }
  }, {})
  return {
    orgMethods: () => {},
    ...exInstances
  }
}


class HelloPlugin {
  static id: 'hello' = 'hello';
  run () {}
}


const foo = someLib({foo: 'foo'},{
  plugins: [HelloPlugin]
})

foo.hello.run()

Singletonであれば、もちろんpropertyに型をマッピングしてもよい。

Discussion