🍞
TypeScriptでオーバーロードありのメソッドの型定義をreadonlyにする
問題点と解決策
Array の reduce メソッドはオーバーロードで設計されています (オーバーロードを使わずElmのように初期値を指定するfoldlと初期値を指定しないfoldl1のように名前を変える設計の方が僕は好きですが...)
間違ってすることはほぼないと思いますが, es5.d.ts
で使用されているメソッドの型定義の書き方では上書き可能です. 動作的にも合ってはいます.
const a = [1, 2, 3];
console.log(a.reduce((acc, val) => acc + val)); // 6
a.reduce = () => 999;
console.log(a.reduce((acc, val) => acc + val)); // 999
class Vector {
constructor(readonly x: number, readonly y: number) {}
distance() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
}
const v = new Vector(3, 4);
console.log(v.distance()); // 5
v.distance = () => 999;
console.log(v.distance()); // 999
ただ, このようなメソッドの上書きによるこの挙動は, 分かりずらいため このように readonlyの関数のプロパティとして定義して上書きを禁止した方が良いです
class Vector {
constructor(readonly x: number, readonly y: number) {}
readonly distance = () => {
return Math.sqrt(this.x * this.x + this.y * this.y);
};
}
const v = new Vector(3, 4);
console.log(v.distance()); // 5
v.distance = () => 999; // Error: Cannot assign to 'distance' because it is a read-only property.
そして, オーバーロードの場合, プロパティとして普通に定義すると重複の名前としてエラーになってしまいます
type Reduce<T> = {
readonly reduce: (
callbackfn: (
previousValue: T,
currentValue: T,
currentIndex: number,
array: T[],
) => T,
) => T;
readonly reduce: <U>( // Duplicate identifier 'reduce'.
callbackfn: (
previousValue: U,
currentValue: T,
currentIndex: number,
array: T[],
) => U,
initialValue: U,
) => U;
};
以下の FnA
と FnB
が同じになることを利用して
import type { Equal, Expect } from "npm:@type-challenges/utils";
type FnA = (a: number, b: number) => number;
type FnB = {
(a: number, b: number): number;
};
type cases = [
Expect<Equal<FnA, FnB>>, // エラーなし
];
このように定義すれば, オーバーロードありのメソッドの型定義をreadonlyにすることができるわけです
type Reduce<T> = {
readonly reduce: {
(
callbackfn: (
previousValue: T,
currentValue: T,
currentIndex: number,
array: T[],
) => T,
): T;
<U>(
callbackfn: (
previousValue: U,
currentValue: T,
currentIndex: number,
array: T[],
) => U,
initialValue: U,
): U;
};
};
@narumincho/readonly
ReadonlyArray
, ReadonlyMap
, ReadonlySet
のような JavaScript で標準的に使われる型のReadonlyバージョンをまとめた @narumincho/readonly というJSRのパッケージを開発しているので, 何か思いついたら Issue, Pull Request を作成してくれるとありがたいです
参考
Discussion