104
68

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 5 years have passed since last update.

TypeScriptのclassは暗黙のうちにinterfaceを定義しているのと同義

Last updated at Posted at 2019-11-04

TypeScriptのclassは、2つの役割がある。

  1. コンストラクタのシグネチャを定義をする
  2. クラスのインスタンスの型をインターフェイスとして定義をする

classinterfaceの線引きが比較的明瞭な言語(JavaやPHPなど)からすると、前者はすんなり理解できるものだが、後者には意外性があるかもしれない。「classを書いたら、interfaceも書いたことになる」ということだからだ。

TypeScriptのclass定義の振る舞いをひとつひとつ確認していこう。

ここに、2つの属性を持ったRectクラスの定義がある。

class Rect {
  x: number = 0
  y: number = 0
}

new クラス名がコンパイルに通るのは、1つ目の「コンストラクタのシグネチャを定義をする」役割によるものである。これは、クラスを使ったことがある経験があれば、何の不思議もないだろう。

const rect = new Rect()

2つ目の役割である「クラスのインスタンスの型をインターフェイスとして定義をする」ことは、TypeScriptの興味深い仕様だ。先のclass Rectのコードの裏で、次のような型定義がなされている:

interface Rect {
  x: number
  y: number
}

型アノテーションでRectが使えるのは、そのためだ。次のコードは、new Rect()の戻り値がRect型であることを表現した一文であるが、これ自体は別段不思議はないだろう:

const rect: Rect = new Rect()
            ^^^^

これと似たようなコードではあるが、次のサンプルコードはTypeScriptらしさがより強く分かる。

const rect: Rect = { x: 3, y: 3 }
                   ^^^^^^^^^^^^^^

rectは型アノテーションでRect型であることを宣言しているが、その値はRectクラスではない。あくまで、Rectインターフェイスを実装したオブジェクトである。このコードはコンパイルがちゃんと通る。

ここまでで、Rectがインターフェイスであることが分かったので、もっとインターフェイスさがよく分かる例を見ていこう。

Rectはインターフェイスなので、普通のinterfaceと同様に、クラスでimplementsすることも当然のようにできる。

class Cube implements Rect {
           ^^^^^^^^^^
  x: number = 0
  y: number = 0
  z: number = 0
}

const rect: Rect = new Cube()

extendsと違うところは、CubeRectを継承しているわけではないというところだ。

Rectはインターフェイスなので、普通のinterfaceの親にすることができる:

interface Cube extends Rect {
^^^^^^^^^      ^^^^^^^
  z: number
}

const cube: Cube = { x: 1, y: 2, z: 3 }
const rect: Rect = cube

Rectはインターフェイスなので、普通のinterface同様にopen-endedの特徴も持っている。したがって、classを定義とは別に、クラスと同名のinterfaceを定義することで、Declaration Mergingを発生させることもできる。

class Rect {
    x: number = 0
    y: number = 0
}

// 追加のインターフェイス定義
interface Rect {
  area(): number
}

上のコードでは、Rectに追加でarea()メソッドを定義している。

もちろん、これだけではarea()メソッドの実装が存在していないので、Rectクラスをnewしただけの次のようなコードでは、コンパイルは通るものの当然ながらランタイムエラーになる。

const rect = new Rect()
rect.area() // runtime error: Uncaught TypeError: rect.area is not a function

所感

参考文献

104
68
3

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
104
68

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?