0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TypeScript でインスタンスでないオブジェクトを渡すコードをコンパイル時に検出する

Last updated at Posted at 2020-05-09

TypeScript で class の constructor で前提条件を満たすようチェックを入れたい。
しかし、クラスがメソッドを持たない public メンバーのみで構成される場合、クラスのインスタンスでないオブジェトを代入できてしまう。

class Klass {
  readonly val: number
  constructor(val: number) {
    if (val < 0) throw new Error("error")
    this.val = val
  }
}
function fn(k: Klass) {}

fn({ val: 1})  // ok
const k: Klass = { val: 1} // ok

色々調べたが、コンパイルオプションなどで検出することはできないようなので、自分なりに方法を考えてみた。

TL;DL

class にダミーのメンバを持たせることでコンパイル時に検出可能。

class Klass {
  readonly val: number
  private _: void
  // 略
}
const k: Klass = { val: 1} // compile error

方法1: instanceof を使う

class Klass {
  // 略
}

function fn(k: Klass) {
  if (!(k instanceof Klass)) throw new Error("error")
}

fn(new Klass(1)) // oK
fn({ val: 1})  // runtime error
const k: Klass = { val: 1 }  // ok

コンパイル時に検出されないし、代入は検出できないのでよろしくない

方法2: ダミーメンバを持たせる

class Klass {
  readonly val: number
  private _: void // 追加
  constructor(val: number) {
    this.val = val
  }
}

function fn(k: Klass) {}

fn(new Klass(1)) // oK
fn({ val: 1})  // compile error
const k: Klass = { val: 1 } // compile error
/*
 * Argument of type '{ val: number; }' is not assignable to parameter of type 'Klass'.
 * Property '_' is missing in type '{ val: number; }' but required in type 'Klass'.
 */

コンパイル時に検出できる。生成されたJSにはメンバ _ は存在しないので、オーバーヘッドもなし。いい感じ。

ダミーメンバの型が void なのは、'_' is declared but its value is never read. を回避するため。

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?