TypeScript satisfies と class

2023/02/04に公開

TypeScript 4.9 から satisfies が登場しましたね。
satisfies と使うことで Widening を防ぎ型推論されるオブジェクトが定義できるようになります。

こちらのスライドがとても良くまとめられていて大変参考になりました。ありがとうございます。
https://speakerdeck.com/tonkotsuboy_com/typescript-4-dot-9noas-const-satisfiesgabian-li-160d825b-7765-4c2b-945d-bb72cc389557

使用例

styled-components で ui library のを作成しているときに使えそうな Util Type です。

type CSSGlobals = 'inherit' | 'initial' | 'revert' | 'unset';

// size
export type Size = Record<string, CSSGlobals | PX | EM | REM>;
type PX = `${string}px`;
type EM = `${string}em`;
type REM = `${string}REM`;

// color
export type Colors = Record<string, 'currentColor' | 'transparent' | CSSGlobals | HEX | RGB | RGBA | HSL | HSLA>;
type HEX = `#${string}`;
type RGB = `rgb(${number}, ${number}, ${number})`;
type RGBA = `rgba(${number}, ${number}, ${number}, ${number})`;
type HSL = `hsl(${string})`;
type HSLA = `hsla(${string})`;

このように宣言しておけば Colors で間違った宣言をしようとするとエラーになります。

satisifes-error

型にメソッドを生やす

as const sastifies を使うだけでも厳格に型をつけられ、型推論もされるようになります。
ここでさらに型にメソッドをもたせたくなってきました。
そんなときどうするか、、、

答えは単純で class を使うです。

基本的なことですが、TypeScript には class があります。
class に値を渡せば、そこで validation をおこなったり、メソッドを追加することができます。

例えば

type Version = `${number}.${number}.${number}`;

Version には "1.2.3" のような . 区切りの数値を文字列で指定するという方になりますが、これにバージョンアップメソッドを生やしたいときは以下のようになります。

type VersionType = `${number}.${number}.${number}`;

class Version {
    value: VersionType;
    private major: number;
    private minor: number;
    private patch: number;

    constructor(value: VersionType) {
        const [major, minor, patch] = value.split('.');
        this.value = value;
        this.major = parseInt(major, 0);
        this.minor = parseInt(minor, 0);
        this.patch = parseInt(patch, 0);
    }

    private update() {
        this.value = `${this.major}.${this.minor}.${this.patch}`;
    }

    majorVersionUp() {
        this.major++;
        this.update();
    }

    minorVersionUp() {
        this.minor++;
        this.update();
    }

    patchVersionUp() {
        this.patch++;
        this.update();
    }
}

const version = new Version('0.0.0');
version.patchVersionUp(); // "0.0.1"
version.minorVersionUp(); // "0.1.1"
version.majorVersionUp(); // "1.1.1"

まとめ

以上 satisifies を使った際にふと気になって、TypeScript の class を復習したメモでした。

Discussion