項目30 入力には寛容に、出力には厳格に
下記の考え方は、ロバストネス原則、またはポステルの法則と呼ばれる
TCPの実装は堅牢性の一般原則に従うべきである。自らの振る舞いに関しては厳格に、他者から受けるものに関しては寛容に
同様のルールが関数の契約にも適応できる
入力として受け入れるものは幅広く(寛容)、出力として生成するのは具体的に(厳格)
出力が寛容だと、出力値を利用する側で様々な考慮が必要になってしまい扱いにくい
特に、オプションプロパティやユニオン型が含まれていると❌️
入力は寛容、出力は厳格に従っている例
code:ts
interface LngLat { lng: number; lat: number; };
type LngLatLike = LngLat | { lon: number; lat: number; } | number, number;
interface Camera {center: LngLat; zoom: number; bearing: number; pitch: number;}
interface CameraOptions extends Omit<Partial<Camera>, 'center'> {
center?: LngLatLike;
}
type LngLatBounds =
{northeast: LngLatLike, southwest: LngLatLike} |
LngLatLike, LngLatLike |
number, number, number, number;
declare function setCamera(camera: CameraOptions): void;
declare function viewportForBounds(bounds: LngLatBounds): Camera;
入力の型と出力の型の間で型を再利用できるよう、出力の型に使う正規の形式と入力の型に使う寛容な形式を導入する
関数の入力に対して反復処理をするだけならT[]ではなく、Iterable<T>を使う(最も寛容な型)
code:ts
function sum(xs: Iterable<number>): number {
let sum = 0;
for (const x of xs) {
sum += x;
}
return sum;
}
入力にジェネレータを渡せる点もGood⭕️
code:ts
function* range(limit: number) {
for (let i = 0; i < limit; i++) {
yield i;
}
}
const zeroToNine = range(10);
// ^? const zeroToNine: Generator<number, void, unknown>
const fortyFive = sum(zeroToNine); // OK、結果は45
#TypeScript