技術記事 by 岡部 健

JavaScript/TypeScriptに自己参照する「型」(type)を与えるtypeself


JavaScriptにはかなりざっくりとした範囲でデータ型(type)があり、typeof 演算子でその型を判定可能ですが、それより細やかなデータ型の区分けが出来たほうが便利です。

JavaScriptに静的型付けの枠組みを与えるのが、TypeScriptですが、まったくユニークな属性を与える型を定義することできません。

typeself (https://github.com/kenokabe/typeself)

では、関数名をユニークな型名とし、任意のデータに型付けが可能です。

もっとも単純な例として、入力をそのまま出力する、ある恒等関数(identity function)Member = a => a をひとつの「型」Type(Member) として定義します。

const  Member  = (a) =>  Type(Member)(a);

このとき、Member関数は入力値aにMember関数自体を属性として追加したaProxyを出力しています。

次にそれぞれの名前(文字列)を値としてもつalicebobを定義しますが、aliceは通常のとおりとし、bobは、すでに定義したMember型を与えながら定義しておきます。

const  alice  =  "Alice";
const  bob  =  Member("Bob");

ユニークな型付けされたデータは、proxyなのでオリジナルと同様の振る舞いをします。ただし、オブジェクトそのものを表示した場合は、proxyオブジェクトであると区別できます。

Type(Member) として型付けされているデータか否かは、
isType(Member)の真偽値(true/false)で判定できます。

log(
"Member status of "  +  alice
);//Member status of Alice
log(
isType(Member)(alice)
);//false
log(
"Member status of "  +  bob
);//Member status of Bob
log(
isType(Member)(bob)
);//true

The original concept introduced in SICP as “TypeTag”.

Install

ESM

ES Modules are distributed as

  • ./dist/build/modules/typeself.js
  • ./dist/build/modules/primitive-obj.js
import { Type, isType } from "./dist/build/modules/typeself.js";

CJS

npm

Using npm:

$ npm i typeself

In Node.js:

const { Type, isType } = require("typeself");

Test

$ node -r esm ./dist/build/index.js

./test/test-typeself.js

import { log } from "./log";
import { Type, isType } from "../modules/typeself";

const test_typeself = () => {
  log("=Are you a member??? ========= ");
  const Member = (a: string) => Type(Member)([a]);
  const alice = "Alice";
  const bob = Member("Bob");
  log(
    "Member status of " + alice
  );//Member status of Alice
  log(
    isType(Member)(alice)
  );//false
  log(
    "Member status of " + bob
  );//Member status of Bob
  log(
    isType(Member)(bob)
  );//true

  log("=Is this a special operation??========= ");
  const specialOperation = (f: Function) => Type(specialOperation)(f);

  const f1 = (a: number) => a + 1; //vanilla function
  const f2 = Type(specialOperation) //typed function
    ((a: number) => {
      //This function might be considered to be "special" 
      //because it does some featured operations in a context.
      return a * 2;
    });

  log(
    isType(specialOperation)(f1)
  );//false
  log(
    f1(1) // f1 = a => a +1
  );//2  // just in case, let you know
  log(
    isType(specialOperation)(f2)
  );//true
  log(
    f2(1) // f2 = a => a * 2
  );//2  // just in case, let you know

  log("=type test of nontyped=========================");
  const I = (a: undefined) => a;  //just a dummy function

  log(
    isType(I)(I) // true
  );
  log(
    isType(I)(1) // false
  );
  log(
    isType(I)([]) // false
  );
  log(
    isType(I)({}) // false
  );
  log(
    isType(I)("hello") //fakse
  );
  log(
    isType(I)((x: undefined) => x) // false
  );
  log(
    isType(I)(true) // false
  );
  log(
    isType(I)(false) // false
  );

  log("=type test of typed=========================");

  log(
    isType(I)(Type(I)(I)) // true
  );
  log(
    isType(I)(Type(I)(1)) // true
  );
  log(
    isType(I)(Type(I)([])) // true
  );
  log(
    isType(I)(Type(I)({})) // true
  );
  log(
    isType(I)(Type(I)("hello")) //true
  );
  log(
    isType(I)(Type(I)((x: undefined) => x)) // true
  );
  log(
    isType(I)(Type(I)(true)) // true
  );
  log(
    isType(I)(Type(I)(false)) // true
  );
  log(
    (Type(I)(false) == false)
      ? "Type(I)(false) == false  (as should be)"
      : "something is wrong"
  );
  log(
    (Type(I)(false) !== false)//Object !== Primitive
      ? "Type(I)(false) !== false  (as should be)"
      : "something is wrong"
  );
  log(
    isType(I)(Type(I)(NaN)) //true
  );
  log(
    isType(I)(Type(I)(undefined)) // false
  );
  log(
    isType(I)(Type(I)(null)) // false
  );

  log("check---------------------------");
  log(
    Type(I)(1) + Type(I)(2)//3
  );
  log(
    Type(I)([1, 2, 3])//[1, 2, 3]
  );

  log("check---------------------------");
  const n = Type(I)(6);
  log(
    n.toString()
  );


};

export { test_typeself };

0 件のコメント:

コメントを投稿