TypeScript の嫌いな理由が分かったかもしれない
これでエラーが起きないことが気に食わないんだ、きっと。
class MountainEntity {
id: number;
name: string;
constructor(
id: number,
name: string,
) {
this.id = id;
this.name = name;
}
}
class Mountain {
id: number;
name: string;
constructor(
id: number,
name: string,
) {
this.id = id;
this.name = name;
}
}
const showMountain = (mountain: Mountain) => {
console.log(mountain);
};
try {
const mountain = new MountainEntity(1, '富士山');
showMountain(mountain);
}
catch(ex) {
console.error(ex);
}
const mountain = new MountainEntity(1, '富士山');
で生成したのは、MountainEntity
であって Mountain
ではない。
showMountain
関数の引数は Mountain
であるのにも関わらず、MountainEntity
を引数に渡してもエラーにならない。
これ、生成されたクラスまで厳格にチェックにいけるのかな?
tsconfig とかで設定できないものなのかな?
これは当然エラーが出る。
class MountainEntity {
id: number;
name: string;
constructor(
id: number,
name: string,
) {
this.id = id;
this.name = name;
}
}
class Mountain {
id: string;
name: string;
constructor(
id: string,
name: string,
) {
this.id = id;
this.name = name;
}
}
const showMountain = (mountain: Mountain) => {
console.log(mountain);
};
try {
const mountain = new MountainEntity(1, '富士山');
showMountain(mountain);
}
catch(ex) {
console.error(ex);
}
id が number と string で違うよってエラー。
Argument of type 'MountainEntity' is not assignable to parameter of type 'Mountain'.
Types of property 'id' are incompatible.
Type 'number' is not assignable to type 'string'.
TypeScript の型推論について詳しく書いてある記事を発見。
ここで気づいていただきたいことは、Hoge型とFuga型は同じ型であるということです。この2つはどちらも{ foo: string; bar: number; }型を指しています(プロパティの順番が違うのは関係ありません)。
Rust で書くと、エラーになる。こうしてほしい。
fn main() {
let bar = Bar {
id: 1,
name: "test".to_string(),
};
show_foo(bar);
}
#[derive(Debug)]
struct Foo {
id: i32,
name: String,
}
#[derive(Debug)]
struct Bar {
id: i32,
name: String,
}
fn show_foo(foo: Foo) {
println!("{:?}", foo);
}
error[E0308]: mismatched types
--> src/main.rs:7:14
|
7 | show_foo(bar);
| -------- ^^^ expected struct `Foo`, found struct `Bar`
| |
| arguments to this function are incorrect
|
note: function defined here
--> src/main.rs:22:4
|
22 | fn show_foo(foo: Foo) {
| ^^^^^^^^ --------
これ、生成されたクラスまで厳格にチェックにいけるのかな?
tsconfig とかで設定できないものなのかな?
Qiita の記事を読む限り、なさそう?
レイヤードアーキテクチャで実装しても、値を詰め替えることなくリターンできちゃうわけだ。
「言われてみれば、そりゃそうだ」って感じだけど、これは嫌だなぁ〜
やはり、Rust が良いよね。Q.E.D.
(過激派)
instanceof
というアイデアがあった。
ただ、「コンパイル時のチェックの対象にはならない」らしい...
自分の目で確かめてみる
コンパイル時にエラーにする書き方が思い付かない...
instanceof
で処理を分岐することはできた。
class MountainEntity {
id: number;
name: string;
constructor(
id: number,
name: string,
) {
this.id = id;
this.name = name;
}
}
class Mountain {
id: number;
name: string;
constructor(
id: number,
name: string,
) {
this.id = id;
this.name = name;
}
}
const showMountain = (mountain: Mountain) => {
if (mountain instanceof Mountain) {
console.log(mountain);
return;
}
console.log(mountain);
};
try {
const mountain = new MountainEntity(1, '富士山');
showMountain(mountain); // MountainEntity が出力される
}
catch(ex) {
console.error(ex);
}
クラスの構造が同じの場合は同じクラスとみなす言語を Structural Typing な言語と言うらしい。