TypeScript – TypeSafe な ArrayObject と 操作

TypeScript - TypeSafe な ArrayObject と 操作

TypeSafe な ArrayObject と ArrayObject の操作
を考えました(あまり実用的では有りません)

環境

VSCode バージョン1.36.1 (1.36.1)

TypeScript とは

型安全で開発可能な AltJS です
Microsoft が主体で開発しています

TypeSafe ではない ArrayObject

const serviceStatusDic = [
  { code: 100, label: "foo" },
  { code: 200, label: "bar" }
];

どのあたりが TypeSafe ではない?

object の key の typo がありえる

もう少し頑張る

object は 任意組み合わせ(ホワイトリスト) にしたい

  • code が 100 の時は、label は foo
  • code が 200 の時は、label は bar

TypeSafe な ArrayObject

VSCode の言語を TypeScript にして貼り付けてみてください
警告がでます 💣

type TypeBase = {
  code: number;
  label: string;
};

class Foo implements TypeBase {
  code!: 100;
  label!: "foo";
}

class Bar implements TypeBase {
  code!: 200;
  label!: "bar";
}

type ServiceStatus = Foo | Bar;

const serviceStatusDic: Readonly<ServiceStatus[]> = [
  { code: 100, label: "foo" }, // OK
  { code: 200, label: "bar" }, // OK
  { cobe: 200, label: "bar" }, // cobe なので エラーになる
  { code: 300, label: "bar" }, // 300 なので エラーになる
  { code: 200, lightNovel: 'bar' }, // なろう系 なので エラーになる
  { code: 200, label: "f00" }, // オレでなきゃ 見逃しちゃうね
  { code: 100, label: "bar" } // 100 と bar の組み合わせ なので エラーになる
];

TypeSafe な ArrayObject 操作

VSCode の言語を TypeScript にして貼り付けてみてください
警告がでます 💣

type Whitelist<T> = T[keyof T];
type WhitelistCode = Whitelist<Pick<ServiceStatus, "code">>;
type WhitelistLabel = Whitelist<Pick<ServiceStatus, "label">>;

const matchCode = (c: WhitelistCode) => (s: ServiceStatus) => s.code === c;
const _findMatchCodeFromServiceStatusDic = (c: WhitelistCode) =>
  serviceStatusDic.find(matchCode(c));
const find = _findMatchCodeFromServiceStatusDic; // alias

// ---
find(100); // {code: 100, label: 'foo'}
find(200); // {code: 200, label: 'bar'}
find(999); // 999はエラーになる

const label100: WhitelistLabel = "foo";
const label200: WhitelistLabel = "bar";
const labelXxx: WhitelistLabel = "xxx"; // xxxはエラーになる

まとめ

別の回答もあるかもしれませんので、探してみてください

追加

ReadonlyDeepReadonly に置き換えるさらに強固

// https://github.com/Microsoft/TypeScript/issues/13923#issue-205837616
type DeepReadonly<T> = {
    readonly [P in keyof T]: DeepReadonly<T[P]>;
}