มีวิธีแยกวิเคราะห์สตริงเป็น JSON ใน typescript หรือไม่
ตัวอย่าง: ใน JS เราสามารถใช้JSON.parse()
ไฟล์. มีฟังก์ชันที่คล้ายกันใน typescript หรือไม่?
ฉันมีสตริงออบเจ็กต์ JSON ดังนี้:
{"name": "Bob", "error": false}
มีวิธีแยกวิเคราะห์สตริงเป็น JSON ใน typescript หรือไม่
ตัวอย่าง: ใน JS เราสามารถใช้JSON.parse()
ไฟล์. มีฟังก์ชันที่คล้ายกันใน typescript หรือไม่?
ฉันมีสตริงออบเจ็กต์ JSON ดังนี้:
{"name": "Bob", "error": false}
JSON.parse
คุณจะได้รับวัตถุเป็นผลลัพธ์ไม่ใช่ a string
(ดูคำตอบของฉันสำหรับข้อมูลเพิ่มเติม) หากคุณต้องการเปลี่ยนวัตถุให้เป็นสตริงคุณต้องใช้JSON.stringify
แทน
คำตอบ:
typescript คือ (superset of) 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);
'{ "myString": "string", "myNumber": 4 }'
โดย'{ "myString": "string", "myNumberBAD": 4 }'
จะไม่ล้มเหลวและ obj.myNumber จะส่งกลับไม่ได้กำหนด
Json.parse(text).validate[MyObj]
คุณจะใช้ playframework.com/documentation/2.6.x/ScalaJsonคุณจะทำสิ่งเดียวกันใน typescript ได้อย่างไร (อาจมีไลบรารีภายนอกให้ทำเช่นนั้น)?
MyObj
ไม่มีรันไทม์ มีเธรดอื่น ๆ มากมายใน SO เกี่ยวกับเรื่องนี้ตัวอย่างเช่นตรวจสอบว่าอ็อบเจ็กต์ใช้อินเทอร์เฟซที่รันไทม์ด้วย TypeScript หรือไม่
JSON.parse
คุณสามารถใช้งานต่อไปได้JSON.parse
เนื่องจาก TS เป็นซูเปอร์เซ็ต JS ยังคงมีปัญหาที่เหลืออยู่: การJSON.parse
ส่งคืนany
ซึ่งทำลายความปลอดภัยของประเภท มีสองตัวเลือกสำหรับประเภทที่แข็งแกร่งกว่า:
ที่กำหนดเองประเภทยามเป็นทางออกที่ง่ายและมักจะเพียงพอสำหรับการตรวจสอบข้อมูลภายนอก:
// 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
เสื้อคลุมแล้วสามารถใช้เป็นชนิดยามเป็น input และคืนแยกวิเคราะห์ค่าพิมพ์:
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
ข้อผิดพลาด
การเขียนฟังก์ชัน type guard ด้วยตนเองจะยุ่งยากหากคุณต้องการตรวจสอบค่าต่างๆ มีไลบรารีที่ช่วยในงานนี้ - ตัวอย่าง (ไม่มีรายการที่ครอบคลุม):
io-ts
: rel. เป็นที่นิยม (3.2k ดาวในปัจจุบัน), fp-ts
การพึ่งพาเพียร์, รูปแบบการเขียนโปรแกรมเชิงฟังก์ชันzod
: ค่อนข้างใหม่ (repo: 2020-03-07) มุ่งมั่นที่จะเป็นขั้นตอน / เชิงวัตถุมากกว่าio-ts
typescript-is
: TS transformer สำหรับ compiler API จำเป็นต้องใช้wrapper เพิ่มเติมเช่นttypescripttypescript-json-schema
/ ajv
: สร้างสคีมา JSON จากประเภทและตรวจสอบความถูกต้องด้วยajv
หากคุณต้องการให้ 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
จะถูกพิมพ์เนื่องจากString
และBoolean
เป็น "หม้อแปลง" ทั้งคู่ในแง่ที่รับอินพุตและส่งคืนเอาต์พุตที่พิมพ์
นอกจากนี้value
จะเป็นประเภทนั้นจริงๆ กล่าวอีกนัยหนึ่งคือถ้าname
เป็นจริง123
มันจะถูกเปลี่ยนเป็นเพื่อ"123"
ให้คุณมีสตริงที่ถูกต้อง เนื่องจากเราใช้String
ที่รันไทม์ซึ่งเป็นฟังก์ชันในตัวที่รับอินพุตโดยพลการและส่งกลับไฟล์string
.
คุณสามารถดูนี้ทำงานที่นี่ ลองทำสิ่งต่อไปนี้เพื่อโน้มน้าวตัวเอง:
const value
คำจำกัดความเพื่อดูว่าป๊อปโอเวอร์แสดงประเภทที่ถูกต้อง"Bob"
ไป123
อีกครั้งเรียกใช้ตัวอย่าง "123"
ในคอนโซลของคุณคุณจะเห็นว่าชื่อที่ได้รับการแปลงอย่างถูกต้องเพื่อสตริงname
เป็นจริง123
มันจะเปลี่ยนเป็น"123"
สิ่งนี้ดูเหมือนจะไม่ถูกต้องของฉันvalue
กำลังจะกลับมา{name: 123..
ไม่ใช่{name:"123"..
ตอนที่ฉันคัดลอกวางโค้ดทั้งหมดของคุณทั้งหมดและทำการเปลี่ยนแปลงนั้น
Transformed
ประเภท คุณสามารถใช้Object
. type Descriptor<T extends Object> = { ... };
Transformed
ชนิดที่ไม่จำเป็นทั้งหมด ฉันได้อัปเดตคำตอบตามนั้น
123
แปลงเป็นสตริงโดยอัตโนมัติ"123"
เนื่องจากเป็นตัวเลขในออบเจ็กต์ JSON
นอกจากนี้คุณยังสามารถใช้ห้องสมุดที่ดำเนินการตรวจสอบประเภทของ JSON ของคุณเช่นSparkson ช่วยให้คุณกำหนดคลาส TypeScript ซึ่งคุณต้องการแยกวิเคราะห์คำตอบของคุณในกรณีของคุณอาจเป็น:
import { Field } from "sparkson";
class Response {
constructor(
@Field("name") public name: string,
@Field("error") public error: boolean
) {}
}
ไลบรารีจะตรวจสอบว่าฟิลด์ที่ต้องการมีอยู่ในเพย์โหลด JSON หรือไม่และประเภทถูกต้องหรือไม่ นอกจากนี้ยังสามารถทำการตรวจสอบความถูกต้องและการแปลงได้อีกด้วย
มีห้องสมุดที่ยอดเยี่ยมสำหรับมัน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 ก่อนที่จะแยกวิเคราะห์
JSON.parse
มีอยู่ใน TypeScript ดังนั้นคุณสามารถใช้งานได้:
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, }
);
typescript มีรันไทม์ JavaScript เนื่องจากคอมไพล์เป็น JS วิธีนี้ JS วัตถุที่มีการสร้างขึ้นในฐานะเป็นส่วนหนึ่งของภาษาเช่นJSON
, Object
และMath
ยังมีใน TS ดังนั้นเราสามารถใช้ไฟล์JSON.parse
วิธีการแยกวิเคราะห์สตริง JSON
const JSONStr = '{"name": "Bob", "error": false}'
// The JSON object is part of the runtime
const parsedObj = JSON.parse(JSONStr);
console.log(parsedObj);
// [LOG]: {
// "name": "Bob",
// "error": false
// }
// The Object object is also part of the runtime so we can use it in TS
const objKeys = Object.keys(parsedObj);
console.log(objKeys);
// [LOG]: ["name", "error"]
สิ่งเดียวในตอนนี้คือ parsedObj เป็นประเภทany
ซึ่งโดยทั่วไปเป็นการปฏิบัติที่ไม่ดีใน TS เราสามารถพิมพ์วัตถุได้หากเราใช้ type guards นี่คือตัวอย่าง:
const JSONStr = '{"name": "Bob", "error": false}'
const parsedObj = JSON.parse(JSONStr);
interface nameErr {
name: string;
error: boolean;
}
function isNameErr(arg: any): arg is nameErr {
if (typeof arg.name === 'string' && typeof arg.error === 'boolean') {
return true;
} else {
return false;
}
}
if (isNameErr(parsedObj)) {
// Within this if statement parsedObj is type nameErr;
parsedObj
}
ใช่มันยุ่งยากเล็กน้อยในTypeScriptแต่คุณสามารถทำตามตัวอย่างด้านล่างได้เช่นนี้
let decodeData = JSON.parse(`${jsonResponse}`);