部分型関係(subtyping relation)について簡単に理解する　TypeScript

# 部分型関係(subtyping relation)について簡単に理解する



**そもそも部分型関係ってなに？？**
部分型とは、2つの型の互換性を表す概念であり、型Sが型Tの部分型であるとは、S型の値がT型の値でもあることを指します。 
>(引用=> プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで)

どういう意味でしょう。
下記のコードを見てみます。
```typescript
type Person={
    name:string;
    age:number;
}

type Student={
    name:string;
    age:number;
    studentNumber:number;
    grade:number;
    class:number;
}
```
このtype文にはPersonとStudentが定義されています。
これは、Student が Person の部分型であると言えます。Student 型のオブジェクトが Person 型としても扱うことができるためです。つまり、Student 型は Person 型のすべてのプロパティを持っており、追加でいくつかのプロパティ（studentNumber、grade、class）を持っています。これにより、Student 型のオブジェクトは Person 型の要件を満たすため、Student は Person の部分型となります。

上記の例で言えば、Student 型のオブジェクトは Person 型の変数に割り当てることができます。これは、Student が Person のすべてのプロパティ（name、age）を持っているため、Person 型として期待されるすべての操作を Student 型のオブジェクトで行うことができるからです。しかし、その逆は成り立ちません。
なぜかというと、Person型のオブジェクトにはStudent特有のプロパティが存在しないのでPerson型をStudent型として扱えないのです。

実際にコードを見てみましょう↓
```typescript
type Person={
    name:string;
    age:number;
}

type Student={
    name:string;
    age:number;
    studentNumber:number;
    grade:number;
    class:number;
}

const taro:Student={
    name:"taro",
    age:20,
    studentNumber:200230002,
    grade:4,
    class:3
}

const  taroInfo:Person = taro;
console.log(taroInfo); 
// { name: 'taro', age: 20, studentNumber: 200230002, grade: 4, class: 3 }
```
このような出力になりました。
動きとしてはPersonの上位互換であるStudent(Personのプロパティ+独自のプロパティがあるため)はPersonのプロパティを持っていることが**保証**されるため、Person型として扱うことができます。

そして変数であるtaroInfoには型注釈としてPersonが指定されており、そこにStudent型のtaroが代入されてます。
先ほども述べた通り、taroは上位互換のStudentであり、Person型が持たなければならないプロパティを**必ず**持っているのでPerson型として扱えるのです。

そして変数taroInfoの中身には基本データ型ではなく、アドレス値(参照)が入っているので、実際にはStudent型のプロパティを含めた値が出力されます。

仮にPerson型にもかかわらず、Studentプロパティにアクセスしようとするとコンパイルエラーになります。

↓コンパイル結果
```terminal
src/index.ts:71:22 - error TS2339: Property 'studentNumber' does not exist on type 'Person'.

71 console.log(taroInfo.studentNumber);
                        ~~~~~~~~~~~~~


Found 1 error in src/index.ts:71
```
これは持っていないプロパティにアクセスするのは危険であり、ミスの可能性が高いので事前にコンパイラが防いでくれているのです。

それでは逆のパターン、Person型のオブジェクトをStudent型で扱ってみましょう。
```typescript
type Person={
    name:string;
    age:number;
}

type Student={
    name:string;
    age:number;
    studentNumber:number;
    grade:number;
    class:number;
}

const taro:Person={
    name:"taro",
    age:20,
}

const taroInfo:Student=taro;
console.log(taroInfo);
```
コンパイル後↓
```terminal
src/index.ts:67:7 - error TS2739: Type 'Person' is missing the following properties from type 'Student': studentNumber, grade, class

67 const taroInfo:Student=taro;
         ~~~~~~~~
Found 1 error in src/index.ts:67
```

Student型には、name,age,studentNumber,grade,classが必須なのにもかかわらず、代入してるtaroの型であるPersonにはnameとageのプロパティしかなくエラーになります。

こうみるとオブジェクト指向言語にある継承と似ていますが少し違います。
比べてみると、部分型関係は型の構造に基づき、明示的な宣言（継承）は必要ありません。一方、継承は明示的な関係を定義し、クラス階層を作成します。


## ここまでをまとめると
部分型関係はプロパティの包含関係によって部分型関係を説明できる
Tが持つプロパティはすべてSにも存在する。
条件1の各プロパティについて、Sにおけるプロパティの型はTにおけるプロパティの型の部分型(または同じ型)である。



# 余剰プロパティに対する型エラーとは？？
オブジェクトリテラルに余計なプロパティが存在すると、コンパイルエラーになることがあります。
勘のいい方なら、余計なプロパティがあっても、部分型関係により問題ないのでは？と疑問になると思います。
その違いをさっそく見ていきます。

```ts
type Person ={
    name:string;
    age:number;
};
const obj:Person={
    name:"hoge",
    age:20,
    tel:"090-####-####"
        //telはPerson型に存在しないためエラー
};
```
このようにコンパイルすると、コメントアウトのようなメッセージが表示されます。
今回代入しようとしたオブジェクトリテラルの型は{name:string; age:number; tel:string}であり、これはPersonの部分型です。それにもかかわらずエラーになるのは、このエラー自体が型安全性とは関係なく、プログラマのミスを防ぐメッセージなのです。
Person型はtelプロパティが存在しないので、そもそもtelプロパティにアクセスすることは許されません。なので実際にtelプロパティを持つオブジェクトをPerson型変数objに直接代入しても、アクセスはどうせ不可能なので、**まったく意味のないコードということがわかります。**

しかし下記のような記述だとエラーメッセージは表示されません。

```ts
type Person ={
    name:string;
    age:number;
};
const obj={
    name:"hoge",
    age:20,
    tel:"090-####-####"
};

const p:Person=obj;
```
これは、まず、型注釈のない変数objが型推論により、{name:string; age:number; tel:string}型となります。
そのobjをPerson型の変数pに代入してますがエラーはでません。
これは{name:string; age:number; tel:string}型がPersonの部分型であり問題がないからです。
pに代入されてる式は生オブジェクトリテラルではなく、変数objであるため、余剰プロパティチェックはされません。これは、変数objが持つプロパティのPerson型の部分だけを利用されて、ほかのところでは、objのtelプロパティが利用されるという側面を持っているためです。
そうすると必ずしも無駄とは言えませんね。

型注釈がある・プロパティを直接代入する。この2条件を満たす場合は無駄かどうかを簡単に判断できるため、このようなチェックが入ります。