classからメソッドを除いた型を作る【TypeScript】

以下のようなコードがあったとき、

class Human {
  constructor(public name: string){}
  SayHello(){
    console.log(`こんにちは。私の名前は${this.name}です。`)
  }
}

const yamada = new Human("山田")
yamada.SayHello()

Human から{ name: string }という型をつくりたいとします。

ですが、SayHelloは型に含めたくないとします。

 

こうときは、以下のようにPickなどで個別のメンバを指定することで実現できます

  • Pick<Human, "name">
  • Exclude<Human, "SayHello">

 

ただ、これだとメンバが増えたときにいちいち修正しないといけないので面倒くさいです。

なのでそういうときは以下のようなコードを書いて、

type NonFunctionPropertyNames<T> = {
  [K in keyof T]: T[K] extends Function ? never : K;
}[keyof T];

export type ExcludeMethods<T> = Pick<T, NonFunctionPropertyNames<T>>;

 

ExcludeMethodsを使ってtype HumanProfile = ExcludeMethods<Human>と書くと、メソッドだけを除いた型を作れます👇

 

ちなみに何故これがしたかったかというと、Firebase FireStoreで以下のようにclassのインスタンスを保存しようとすると「プリミティブなオブジェクトしか受け付けへんで」的なエラーが出たからです。

class Human {
  constructor(public name: string){}
  SayHello(){
    console.log(`こんにちは。私の名前は${this.name}です。`)
  }
}

const yamada = new Human("山田")

const docRef = doc("collection", "id");
await setDoc(docRef, yamada);  //❌これはダメらしい

 

以下のような感じにすると行けました。

class Human {
  constructor(public name: string){}
  SayHello(){
    console.log(`こんにちは。私の名前は${this.name}です。`)
  }
  GetPrimitive(): HumanProfile{
    return {...this}
  }
}

const yamada = new Human("山田")

const docRef = doc("collection", "id");
await setDoc(docRef, yamada.GetPrimitive());//✅これだと行ける

 

なんか「もっとスマートにできないの?」感はありますが、他に方法が思いつきませんでした。。

というかそもそも、なんでclassのインスタンスをそのまま保存できるようになってないんだろう。めちゃ不便じゃね・・?

 

おわり

 

参考:

How to create a type excluding instance methods from a class in typescript? – Stack Overflow

angular – Firestore: Add Custom Object to db – Stack Overflow

コメント

タイトルとURLをコピーしました