2019年6月9日日曜日

TypeScriptでJSON型情報

先週にひきつづき、今度はJSONで使われるデータの型情報("null"とか"string"とか)を取得してみます。

ほら、ウェブアプリケーションを作るときに使えそうじゃないですか。え?使わない?まあそう言わずに。

やりたいこと

  • 引数にnullを渡したら"null"という文字列を
  • 引数に真偽値を渡したら"boolean"という文字列を
  • 引数に数値を渡したら"number"という文字列を
  • 引数に文字列を渡したら"string"という文字列を
  • 引数に配列を渡したら"[<配列の要素の型名>]"という文字列を
  • 引数にオブジェクトを渡したら"{<キーの型名>:<値の型名>}"という文字列を
返す関数を作りたい。
名前はjsonTypeとしておきます。

ダメだった例

これはダメです。
function jsonType(value: any): string {
    return typeof value;
}
何がダメかというと、typeof nulltypeof []"object"を返すからです。
そしてtypeof {}"{}"を返してほしいのに"object"を返します。

うまくいった例

これは先週のように頭をひねる要素はないのでサクッと正解を書いてしまいます。
配列やオブジェクトに再帰を使うだけです。
/**
 * 型情報を再帰的に取得
 * @param value 調査対象
 * @returns 型名
 */
function jsonType(value: any): string {
 if (value === null) {
  return "null";
 }
 if (Array.isArray(value)) {
  return jsonTypeArray(value);
 }

 const typename = typeof value;
 if (typename === "object") {
  return jsonTypeObject(value);
 }
 return typename;
}

/**
 * 型情報を再帰的に取得: 配列
 * @param value 調査対象(配列型)
 * @returns 型名
 */
function jsonTypeArray(value: any[]): string {
 const types: string[] = [];
 for (const v of value) {
  // 各要素を再帰処理
  types.push(jsonType(v));
 }
 return `[${types.join(",")}]`;
}

/**
 * 型情報を再帰的に取得: オブジェクト
 * @param value 調査対象(オブジェクト型)
 * @returns 型名
 */
function jsonTypeObject(value: {[key: string]: any}): string {
 const types: string[] = [];
 for (const k of Object.keys(value)) {
  // 各要素を再帰処理; キーはエスケープしておく
  types.push(`${JSON.stringify(k)}:${jsonType(value[k])}`);
 }
 return `{${types.join(",")}}`;
}

// テスト
const
    a = null,
    b = false,
    c = 0,
    d = "",
    e = [a, b, c, d],
    f = { a, b, c, d, e },
    g = [e, f];

console.log(jsonType(a) === 'null');
console.log(jsonType(b) === 'boolean');
console.log(jsonType(c) === 'number');
console.log(jsonType(d) === 'string');
console.log(jsonType(e) === '[null,boolean,number,string]');
console.log(jsonType(f) === '{"a":null,"b":boolean,"c":number,"d":string,"e":[null,boolean,number,string]}');
console.log(jsonType(g) === '[[null,boolean,number,string],{"a":null,"b":boolean,"c":number,"d":string,"e":[null,boolean,number,string]}]');

注意事項

再帰で死ぬのでこういうことはやらないように。
const data: any = {};
data.abc = data;
jsonType(data);

0 件のコメント:

コメントを投稿