TypescriptでJSON文字列を解析する方法


99

Typescriptで文字列をJSONとして解析する方法はありますか?
例:JSでは、を使用できますJSON.parse()。Typescriptに同様の関数はありますか?

次のようなJSONオブジェクト文字列があります。

{"name": "Bob", "error": false}

1
そのホームページでは、「TypeScriptは、単純なJavaScriptにコンパイルされるJavaScriptの型付きスーパーセット」であると述べています。JSON.parse()関数は、通常のように使用できる必要があります。
sigalor

1
Atomテキストエディターを使用していて、JSON.parseを実行すると、次のエラーが表示されます。タイプ '{}'の引数はタイプ 'string'のパラメーターに割り当てられません
ssd20072

21
これは非常に基本的な質問であり、一部の人にとってはささいなことのように思えるかもしれませんが、それでも有効な質問であり、SOには同等のものが見つからないため、質問を続けない理由はありません。私の意見では、同様に反対票を投じるべきではありません。
Nitzan Tomer 2016

2
@SanketDeshpandeを使用JSON.parseすると、結果としてオブジェクトではなくオブジェクトが取得されますstring(詳細については、私の回答を参照してください)。オブジェクトを文字列に変換したい場合は、JSON.stringify代わりに使用する必要があります。
Nitzan Tomer 2016

2
実際には、2つの理由から単純な質問ではありません。まず、JSON.parse()は同じ種類のオブジェクトを返しません-一部のインターフェースに一致しますが、アクセサーなどのインテリジェントなものは存在しません。さらに、確かに私たちは人々がグーグルのものであるときに人々が行くところにSOになりたいですか?
種不明

回答:


165

Typescriptはjavascript(のスーパーセット)なので、javascriptと同じように使用JSON.parseできます。

let obj = JSON.parse(jsonString);

typescriptでのみ、結果のオブジェクトに型を持つことができます。

interface MyObj {
    myString: string;
    myNumber: number;
}

let obj: MyObj = JSON.parse('{ "myString": "string", "myNumber": 4 }');
console.log(obj.myString);
console.log(obj.myNumber);

遊び場のコード


9
入力が有効であることを検証する方法(typescript、typescriptの目的の1つ)入力を交換する'{ "myString": "string", "myNumber": 4 }'ことにより、'{ "myString": "string", "myNumberBAD": 4 }'失敗することはありません、とobj.myNumberは未定義を返します。
David Portabella、2017

2
@DavidPortabella文字列の内容に対して型チェックを行うことはできません。これはランタイムの問題であり、型チェックはコンパイル時のためです
Nitzan Tomer '25

2
OK。typescript objが実行時にインターフェイスを満たすことをどのように検証できますか?つまり、この例ではmyNumberが未定義ではありません。たとえば、Scala Playではを使用しますJson.parse(text).validate[MyObj]playframework.com/documentation/2.6.x/ScalaJson typescriptで同じようにするにはどうすればよいですか(そうするための外部ライブラリがあるのでしょうか?)?
David Portabella

1
@DavidPortabella実行時MyObjは存在しないため、簡単にはできません。たとえば、この件に関しては、SOには他にもたくさんのスレッドがあります。たとえば、オブジェクトが実行時にTypeScriptを使用してインターフェイスを実装しているかどうかを確認します
Nitzan Tomer

7
わかりました、ありがとう。毎日、私はscalajsの使用に確信を持っています。
David Portabella、2017

5

タイプセーフ JSON.parse

JSON.parseTSはJSスーパーセットであるため、引き続き使用できます。まだ問題がありJSON.parseますany。タイプセーフティを損なうreturnです。より強力なタイプの2つのオプションを次に示します。

1.ユーザー定義のタイプガード(遊び場

カスタムタイプガードは最も単純なソリューションであり、多くの場合、外部データの検証には十分です。

// For example, you expect to parse a given value with `MyType` shape
type MyType = { name: string; description: string; }

// Validate this value with a custom type guard
function isMyType(o: any): o is MyType {
  return "name" in o && "description" in o
}

JSON.parseラッパーは、入力としてタイプガードを取り、解析され、入力した値を返すことができます。

const safeJsonParse = <T>(guard: (o: any) => o is T) => (text: string): ParseResult<T> => {
  const parsed = JSON.parse(text)
  return guard(parsed) ? { parsed, hasError: false } : { hasError: true }
}

type ParseResult<T> =
  | { parsed: T; hasError: false; error?: undefined }
  | { parsed?: undefined; hasError: true; error?: unknown }
使用例:
const json = '{ "name": "Foo", "description": "Bar" }';
const result = safeJsonParse(isMyType)(json) // result: ParseResult<MyType>
if (result.hasError) {
  console.log("error :/")  // further error handling here
} else {
  console.log(result.parsed.description) // result.parsed now has type `MyType`
}

safeJsonParse高速失敗するか、JSON.parseエラーを試行/キャッチするように拡張される場合があります。

2.外部ライブラリ

多くの異なる値を検証する必要がある場合、タイプガード関数を手動で記述するのは面倒になります。このタスクを支援するライブラリがあります-例(包括的なリストはありません):

  • io-ts:rel。ポピュラー(現在は3.2kスター)、fp-tsピア依存、関数型プログラミングスタイル
  • zod:(レポ:2020年3月7日)は非常に新しい、努力するが、より可能にする手続き/オブジェクト指向よりio-ts
  • typescript-is:コンパイラAPIのTSトランスフォーマー、ttypescriptのような追加のラッパーが必要
  • typescript-json-schema/ ajv:タイプからJSONスキーマを作成し、それを使用して検証しますajv

詳細情報


4

JSONに検証済みのTypescriptタイプを持たせたい場合は、その検証作業を自分で行う必要があります。これは新しいことではありません。単純なJavascriptでは、同じことをする必要があります。

検証

検証ロジックを「変換」のセットとして表現したい。私Descriptorは変換のマップとして定義します:

type Descriptor<T> = {
  [P in keyof T]: (v: any) => T[P];
};

次に、これらの変換を任意の入力に適用する関数を作成できます。

function pick<T>(v: any, d: Descriptor<T>): T {
  const ret: any = {};
  for (let key in d) {
    try {
      const val = d[key](v[key]);
      if (typeof val !== "undefined") {
        ret[key] = val;
      }
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      throw new Error(`could not pick ${key}: ${msg}`);
    }
  }
  return ret;
}

これで、JSON入力を検証するだけでなく、Typescriptタイプを構築しています。上記のジェネリック型は、結果が「変換」から型を推測することを保証します。

変換がエラーをスローする場合(検証を実装する方法です)、エラーの原因となったキーを示す別のエラーでラップします。

使用法

あなたの例では、私はこれを次のように使用します:

const value = pick(JSON.parse('{"name": "Bob", "error": false}'), {
  name: String,
  error: Boolean,
});

value以来、型付けされますStringBoolean、彼らは入力を取り、型指定された出力を返すという意味で、両方の「変圧器」です。

さらに、value意志は実際にもそのタイプ。つまり、name実際123"123"だった場合、有効な文字列が得られるように変換されます。これはString、実行時に任意の入力を受け入れてを返す組み込み関数を使用したためstringです。

ここでこれが機能しているのを見ることができます。次のことを試して、納得してください。

  • const value定義にカーソルを合わせると、ポップオーバーに正しいタイプが表示されます。
  • サンプルに変更"Bob"123て再実行してみてください。コンソールで、名前が文字列に正しく変換されていることがわかります"123"

場合は」、例を挙げたname実際にして123、それはに変換されます"123"。これは正しくないように思わ私は。。value戻って来ている{name: 123..ではない{name:"123"..、私は正確にすべてのコードを貼り付けて、その変更を行うコピーするとき。
Joncom

奇妙なことに、それは私には有効です。ここで試してください:typescriptlang.org/play/index.html(の123代わりに使用"Bob")。
チョコレート

Transformedタイプを定義する必要はないと思います。そのまま使えますObjecttype Descriptor<T extends Object> = { ... };
lovasoa

@lovasoaに感謝します、あなたは正しいです。Transformedタイプは全く不要です。それに応じて答えを更新しました。
Chowey

1

さらに、Sparksonなど、jsonの型検証を実行するライブラリを使用できます。それらはあなたがあなたの応答を解析したいTypeScriptクラスを定義することを可能にします。

import { Field } from "sparkson";
class Response {
   constructor(
      @Field("name") public name: string,
      @Field("error") public error: boolean
   ) {}
}

ライブラリーは、必須フィールドがJSONペイロードに存在するかどうか、およびそれらのタイプが正しいかどうかを検証します。また、一連の検証と変換を行うこともできます。


あなたは上記のライブラリの主な貢献者であることに言及する必要があります。
ford04

1

それのための素晴らしいライブラリがありますts-json-object

あなたの場合、次のコードを実行する必要があります:

import {JSONObject, required} from 'ts-json-object'

class Response extends JSONObject {
    @required
    name: string;

    @required
    error: boolean;
}

let resp = new Response({"name": "Bob", "error": false});

このライブラリは、解析する前にjsonを検証します


0

JSON.parse TypeScriptで利用できるので、そのまま使用できます。

JSON.parse('{"name": "Bob", "error": false}') // Returns a value of type 'any'

ただし、多くの場合、typeの値を処理するのではなく、特定の型と一致することを確認しながら、JSONオブジェクトを解析する必要がありますany。その場合、次のような関数を定義できます。

function parse_json<TargetType extends Object>(
  json: string,
  type_definitions: { [Key in keyof TargetType]: (raw_value: any) => TargetType[Key] }
): TargetType {
  const raw = JSON.parse(json); 
  const result: any = {};
  for (const key in type_definitions) result[key] = type_definitions[key](raw[key]);
  return result;
}

この関数は、JSON文字列と、作成するオブジェクトの各フィールドをロードする個々の関数を含むオブジェクトを受け取ります。次のように使用できます。

const value = parse_json(
  '{"name": "Bob", "error": false}',
  { name: String, error: Boolean, }
);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.