TypeScript 実行時にオブジェクトの構造をチェックする

io-tsを使用する

新しいプロジェクトを作成し、typescript、io-ts、fp-ts を install します。

$ mkdir iots-test
$ cd iots-test
$ npm init -y
$ npm install typescript io-ts fp-ts

src 配下に app.ts を作成します。

const str: string = '123';
console.log(str);

コンパイルして実行すると、123 が出力されることを確認します。

$ npx tsc src/app.ts
$ node src/app.js
123

環境構築は完了です。

io-tsサンプルコード

使い方があっているかいまいち自信がありません。

import * as t from 'io-ts';
import { PathReporter} from "io-ts/PathReporter";
import {isLeft} from "fp-ts/Either";


//古い商品オブジェクトはisOldがtrue、かつ、idがstring
//新しい商品オブジェクトはisOldがfalse、かつ、idがnumber
//どちらがくるかは実行するタイミングでないと分からない場合に、isOldがtrueかfalseかを見て、オブジェクトの構造が正しいかをチェックしたい

const OldProduct = t.type({
   isOld: t.boolean,
   id: t.string
});
const NewProduct = t.type({
    isOld: t.boolean,
    id: t.number
});
const Product = t.union([OldProduct, NewProduct]);
type Product = t.TypeOf<typeof Product>

const product = new t.Type<Product>(
  'Product',
  Product.is,
    (input, _) => {
      const decoded = Product.decode(input);
      if(isLeft(Product.decode(input))) return decoded;

      if(input["isOld"]){
          console.log("@@@old product");
          return OldProduct.decode(input);
      }else{
          console.log("@@@new product");
          return NewProduct.decode(input);
      }
    },
    t.identity
);

//動作確認
const validOldProduct = {
    isOld: true,
    id: "100"
};
const invalidOldProduct = {
    isOld: true,
    id: 100
};
const validNewProduct = {
    isOld: false,
    id: 100
};
const invalidNewProduct = {
    isOld: false,
    id: "100"
};
const invalidObj = {
  name: 'tamibouz'
};

console.log(PathReporter.report(product.decode(validOldProduct))); //[ 'No errors!' ]
console.log(PathReporter.report(product.decode(invalidOldProduct)));// [ 'Invalid value 100 supplied to : { isOld: boolean, id: string }/id: string' ]
console.log(PathReporter.report(product.decode(validNewProduct)));//[ 'No errors!' ]
console.log(PathReporter.report(product.decode(invalidNewProduct)));//[ 'Invalid value "100" supplied to : { isOld: boolean, id: number }/id: number' ]
console.log(PathReporter.report(product.decode(invalidObj)));

product 中で分岐すると、product が複雑になってしまうので、分岐は外でやってもいいかもしれません。