टाइपस्क्रिप्ट में JSON स्ट्रिंग को पार्स करने के लिए कैसे


108

टाइपस्क्रिप्ट में JSON के रूप में तार पार्स करने का एक तरीका है।
उदाहरण: JS में, हम उपयोग कर सकते हैं JSON.parse()। क्या टाइपस्क्रिप्ट में समान कार्य है?

मेरे पास JSON ऑब्जेक्ट स्ट्रिंग निम्नानुसार है:

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

1
इसके मुखपृष्ठ पर, यह कहता है कि "टाइपस्क्रिप्ट जावास्क्रिप्ट का एक टाइप किया हुआ सुपरसेट है जो सादे जावास्क्रिप्ट के लिए संकलित है"। JSON.parse () फ़ंक्शन सामान्य की तरह प्रयोग करने योग्य होना चाहिए।
२१:२२ पर सिगलोर जूल

1
मैं एटम पाठ संपादक का उपयोग कर रहा हूं और जब मैं एक JSON.parse करता हूं, तो मुझे त्रुटि मिलती है: टाइप '{}' का तर्क 'स्ट्रिंग' के पैरामीटर के लिए लागू नहीं है
ssd20072

22
यह एक बहुत ही बुनियादी सवाल है, और यह कुछ के लिए मामूली लग सकता है, लेकिन यह एक वैध सवाल है कोई भी कम नहीं है, और एक बराबर एसओ में नहीं पाया जा सकता है (मैं नहीं है) इसलिए कोई वास्तविक कारण नहीं है कि सवाल क्यों नहीं रखा जाए चल रहा है, और मेरी राय में नीचे वोट नहीं किया जाना चाहिए।
नीत्तन तोमर

2
@SanketDeshpande जब आप उपयोग करते हैं JSON.parseतो आपको एक परिणाम के रूप में एक वस्तु मिलती है और एक नहीं string(अधिक के लिए मेरा उत्तर देखें)। यदि आप किसी ऑब्जेक्ट को स्ट्रिंग में बदलना चाहते हैं, तो आपको JSON.stringifyइसके बजाय उपयोग करने की आवश्यकता है ।
नीत्तन तोमर

2
वास्तव में यह 2 कारणों से एक साधारण प्रश्न नहीं है। सबसे पहले, JSON.parse () एक ही तरह की वस्तु नहीं लौटाता है - यह कुछ इंटरफ़ेस से मेल खाएगा, लेकिन कुछ भी, जैसे कि एक्सेसरीज़, कुछ भी मौजूद नहीं होगा। इसके अलावा, निश्चित रूप से हम चाहते हैं कि एसओ वही हो जहां लोग जाते हैं जब वे Google सामान लेते हैं?
speciesUnknown

जवाबों:


175

टाइपस्क्रिप्ट जावास्क्रिप्ट का (एक सुपरसेट) है, इसलिए आप बस उसी तरह का उपयोग करते हैं JSON.parseजैसा आप जावास्क्रिप्ट में करते हैं:

let obj = JSON.parse(jsonString);

केवल उस टाइपस्क्रिप्ट में आप परिणामस्वरूप ऑब्जेक्ट के लिए एक प्रकार हो सकते हैं:

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

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

( खेल के मैदान में कोड )


9
कैसे मान्य है कि इनपुट वैध है (टाइप-चेकिंग, टाइपस्क्रिप्ट के उद्देश्यों में से एक)? '{ "myString": "string", "myNumber": 4 }'द्वारा इनपुट को प्रतिस्थापित करना '{ "myString": "string", "myNumberBAD": 4 }'विफल नहीं होगा, और obj.myNumber अपरिभाषित वापस आ जाएगा।
डेविड पोर्टेबेला

3
@DavidPortabella आप एक स्ट्रिंग की सामग्री पर टाइप-जाँच नहीं कर सकते। यह एक रनटाइम इश्यू है, और टाइप चेकिंग संकलन समय के लिए है
निट्ज़ैन तोमर

2
ठीक है। मैं यह कैसे मान्य कर सकता हूं कि एक टाइपस्क्रिप्ट obj रनटाइम में इसके इंटरफेस को संतुष्ट करता है? यह है, कि myNumber इस उदाहरण में अपरिभाषित नहीं है। उदाहरण के लिए, स्काला प्ले में, आप उपयोग करेंगे Json.parse(text).validate[MyObj]playframework.com/documentation/2.6.x/ScalaJson आप टाइपस्क्रिप्ट में समान कैसे कर सकते हैं (शायद ऐसा करने के लिए कोई बाहरी पुस्तकालय है?)।
डेविड पोर्टेबेला

1
@DavidPortabella ऐसा करने का कोई तरीका नहीं है, आसानी से नहीं, क्योंकि रनटाइम पर MyObjमौजूद नहीं है। इस विषय के बारे में SO में बहुत सारे अन्य सूत्र हैं, उदाहरण के लिए: देखें कि क्या ऑब्जेक्ट टाइपस्क्रिप्ट के साथ रनटाइम पर एक इंटरफ़ेस लागू करता है
Nitzan Tomer

7
ठीक है धन्यवाद। रोज मैं स्केलाज का उपयोग करने के बारे में अधिक आश्वस्त हूं।
डेविड पोर्टाबेला

7

टाइप-सुरक्षित JSON.parse

आप उपयोग करना जारी रख सकते हैं JSON.parse, क्योंकि TS एक JS सुपरसेट है। अभी भी एक समस्या बाकी है: JSON.parseरिटर्न any, जो प्रकार की सुरक्षा को कमजोर करता है। यहाँ मजबूत प्रकारों के लिए दो विकल्प दिए गए हैं:

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: जारी करें। लोकप्रिय (वर्तमान में 3.2k सितारे), fp-tsसहकर्मी निर्भरता, कार्यात्मक प्रोग्रामिंग शैली
  • zod: काफी नया (रेपो: 2020-03-07), इससे अधिक प्रक्रियात्मक / वस्तु-उन्मुख होने का प्रयास करता हैio-ts
  • typescript-is: कंपाइलर एपीआई के लिए टीएस ट्रांसफॉर्मर, अतिरिक्त रैपर जैसे ttypescript की जरूरत
  • typescript-json-schema/ ajv: टाइप से JSON स्कीमा बनाएं और इसे मान्य करेंajv

अधिक infos


4

यदि आप चाहते हैं कि आपका JSON एक मान्य टाइपस्क्रिप्ट प्रकार का हो, तो आपको वह सत्यापन स्वयं करने की आवश्यकता होगी। यह कोई नई बात नहीं है। सादे जावास्क्रिप्ट में, आपको वही करने की आवश्यकता होगी।

मान्यकरण

मुझे "ट्रांसफ़ॉर्म" के सेट के रूप में अपना सत्यापन तर्क व्यक्त करना पसंद है। मैं 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 इनपुट को सत्यापित कर रहा हूं, बल्कि मैं टाइपस्क्रिप्ट टाइप भी बना रहा हूं। उपरोक्त सामान्य प्रकार यह सुनिश्चित करते हैं कि परिणाम आपके "रूपांतरों" से प्रकारों को संक्रमित करता है।

मामले में परिवर्तन एक त्रुटि फेंकता है (जो है कि आप सत्यापन कैसे लागू करेंगे), मैं इसे एक और त्रुटि के साथ लपेटना पसंद करता हूं जिसमें यह त्रुटि दिखाई देती है।

प्रयोग

आपके उदाहरण में, मैं इसका उपयोग इस प्रकार करूंगा:

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

अब value, आपके द्वारा लिखा गया हो जाएगा के बाद से Stringऔर Booleanकर रहे हैं दोनों "ट्रांसफॉर्मर" भावना वे इनपुट लेने के लिए और एक टाइप किया उत्पादन लौटने में।

इसके अलावा, valueइच्छा वास्तव में हो सकता है कि टाइप। दूसरे शब्दों में, यदि nameवास्तव में थे , तो 123इसे रूपांतरित किया जाएगा "123"ताकि आपके पास एक वैध स्ट्रिंग हो। इसका कारण यह है कि हम Stringरनटाइम पर उपयोग करते हैं, एक अंतर्निहित फ़ंक्शन जो मनमाना इनपुट स्वीकार करता है और एक रिटर्न देता है string

आप यहां काम करते हुए देख सकते हैं । अपने आप को समझाने के लिए निम्नलिखित बातों को आज़माएँ:

  • const valueयह देखने के लिए कि पॉप-ओवर सही प्रकार दिखाता है परिभाषा पर होवर करें।
  • नमूना को फिर से चलाने और बदलने "Bob"का प्रयास करें 123। आपके कंसोल में, आप देखेंगे कि नाम ठीक से स्ट्रिंग में परिवर्तित हो गया है "123"

आपको एक उदाहरण दिया था, "यदि nameवास्तव में थे 123, यह करने के लिए परिवर्तित हो जाएगा "123"यह गलत हो रहा है मेरे।। valueवापस आ रहा है {name: 123..नहीं {name:"123"..है जब मैं अपने सभी कोड वास्तव में पेस्ट करें और यह बदलाव लाना कॉपी।
Joncom

अजीब है, यह मेरे लिए काम करता है। इसे यहाँ आज़माएँ: typecriptlang.org/play/index.html ( 123इसके बजाय का उपयोग करके "Bob")।
चौबे

मुझे नहीं लगता कि आपको एक Transformedप्रकार को परिभाषित करने की आवश्यकता है । आप बस इस्तेमाल कर सकते हैं Objecttype Descriptor<T extends Object> = { ... };
लवणसोआ

धन्यवाद @lovasoa, आप सही हैं। Transformedप्रकार पूरी तरह अनावश्यक है। मैंने उसी हिसाब से जवाब अपडेट किया है।
चौबे

यदि आप वास्तव में यह सत्यापित करना चाहते हैं कि JSON ऑब्जेक्ट के सही प्रकार हैं, तो आप स्वचालित रूप से स्ट्रिंग में परिवर्तित नहीं होना चाहेंगे , क्योंकि यह JSON ऑब्जेक्ट का एक नंबर है। 123"123"
xuiqzy

1

आप अतिरिक्त रूप से पुस्तकालयों का उपयोग कर सकते हैं जो स्पार्कसन जैसे आपके जोंस का प्रकार सत्यापन करते हैं । वे आपको टाइपस्क्रिप्ट क्लास को परिभाषित करने की अनुमति देते हैं, जिसमें आप अपनी प्रतिक्रिया को पार्स करना चाहते हैं, आपके मामले में यह हो सकता है:

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

यदि आवश्यक क्षेत्र JSON पेलोड में मौजूद हैं और यदि उनके प्रकार सही हैं, तो पुस्तकालय मान्य करेगा। यह मान्यताओं और रूपांतरणों का एक समूह भी कर सकता है।


1
आपको उल्लेख करना चाहिए, कि आप उपरोक्त पुस्तकालय के मुख्य योगदानकर्ता हैं।
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});

यह लाइब्रेरी पार्स करने से पहले जोंस को मान्य करेगी


0

JSON.parse टाइपस्क्रिप्ट में उपलब्ध है, इसलिए आप इसका उपयोग कर सकते हैं:

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

हालाँकि, आप अक्सर एक 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, }
);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.