Dizeleri Typecript'te JSON olarak ayrıştırmanın bir yolu var mı?
Örnek: JS'de kullanabiliriz JSON.parse(). Typescript'te benzer bir işlev var mı?
Aşağıdaki gibi bir JSON nesne dizim var:
{"name": "Bob", "error": false}
Dizeleri Typecript'te JSON olarak ayrıştırmanın bir yolu var mı?
Örnek: JS'de kullanabiliriz JSON.parse(). Typescript'te benzer bir işlev var mı?
Aşağıdaki gibi bir JSON nesne dizim var:
{"name": "Bob", "error": false}
JSON.parsesonuç olarak bir nesne alırsınız, a değil string(daha fazlası için cevabıma bakın). Bir nesneyi dizeye dönüştürmek istiyorsanız, JSON.stringifybunun yerine kullanmanız gerekir .
Yanıtlar:
Typescript (bir üst kümesi) javascript, yani javascript'te yaptığınız JSON.parsegibi kullanın :
let obj = JSON.parse(jsonString);
Sadece typcript'te ortaya çıkan nesnenin bir türüne sahip olabilirsiniz:
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 }'tarafından '{ "myString": "string", "myNumberBAD": 4 }'başarısız olmayacak ve obj.myNumber tanımsız dönecektir.
Json.parse(text).validate[MyObj]. playframework.com/documentation/2.6.x/ScalaJson aynısını typcript'te nasıl yapabilirsiniz (bunu yapmak için harici bir kütüphane olabilir?)?
MyObjmevcut değil. SO'da
JSON.parseJSON.parseTS bir JS üst kümesi olduğu için kullanmaya devam edebilirsiniz . Hala bir sorun var: tür güvenliğini baltalayan JSON.parsedönüşler any. Daha güçlü türler için iki seçenek şunlardır:
Özel tip korumalar en basit çözümdür ve genellikle harici veri doğrulama için yeterlidir:
// 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
}
Daha JSON.parsesonra bir sarmalayıcı, girdi olarak bir tür koruması alabilir ve ayrıştırılmış, yazılan değeri döndürebilir:
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 }
Kullanım örneği:
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`
}
safeJsonParsehızlı başarısız olmak veya dene / yakala JSON.parsehataları için uzatılabilir .
Birçok farklı değeri doğrulamanız gerekiyorsa, yazı koruma işlevlerini manuel olarak yazmak zahmetli hale gelir. Bu göreve yardımcı olacak kitaplıklar var - örnekler (kapsamlı liste yok):
io-ts: rel. popüler (şu anda 3,2 bin yıldız), fp-tsakran bağımlılığı, işlevsel programlama stilizod: Oldukça yeni (Repo: 2020/03/07), rekabetin bu fazla olduğu usul / nesne yönelimli dahaio-tstypescript-is: Derleyici API'si için TS transformatörü, ttypescript gibi ek sarmalayıcı gereklitypescript-json-schema/ ajv: Türlerden JSON şeması oluşturun ve şununla doğrulayın:ajvJSON'nizin doğrulanmış bir Typescript türüne sahip olmasını istiyorsanız, bu doğrulama çalışmasını kendiniz yapmanız gerekecektir. Bu yeni bir şey değil. Düz Javascript'te aynısını yapmanız gerekir.
Doğrulama mantığımı bir dizi "dönüşüm" olarak ifade etmeyi seviyorum. Bir Descriptordönüşüm haritası olarak tanımlıyorum :
type Descriptor<T> = {
[P in keyof T]: (v: any) => T[P];
};
Sonra bu dönüşümleri rastgele girdilere uygulayacak bir fonksiyon yapabilirim:
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;
}
Şimdi, yalnızca JSON girdimi doğrulamakla kalmıyorum, aynı zamanda ilerledikçe bir Typecript türü oluşturuyorum. Yukarıdaki genel türler, sonucun "dönüşümlerinizden" türlere ulaşmasını sağlar.
Dönüşümün bir hata atması durumunda (bu, doğrulama işlemini nasıl gerçekleştirirsiniz), onu hangi anahtarın hataya neden olduğunu gösteren başka bir hatayla sarmayı tercih ederim.
Örneğinizde bunu şu şekilde kullanırım:
const value = pick(JSON.parse('{"name": "Bob", "error": false}'), {
name: String,
error: Boolean,
});
Şimdi valuebu yana, daktilo edilecek Stringve Booleanbunlar girişi çekmek ve daktilo çıktı dönmek anlamda hem "transformatörleri" dir.
Ayrıca, valueirade aslında olması o türü. Başka bir deyişle, eğer namegerçekten öyleyse, geçerli bir dizeye sahip olmanız 123için dönüştürülecektir "123". Bunun nedeni String, rasgele girdiyi kabul eden ve a döndüren yerleşik bir işlev olan çalışma zamanında kullanmış olmamızdır string.
Bunun çalıştığını burada görebilirsiniz . Kendinizi ikna etmek için aşağıdaki şeyleri deneyin:
const valueAçılır pencerenin doğru türü gösterdiğini görmek için imleci tanımın üzerine getirin ."Bob"için 123ve örnek yeniden çalıştırın. Konsolunuzda, ismin düzgün bir şekilde dizeye dönüştürüldüğünü göreceksiniz "123".nameaslında edildi 123, bu dönüştürülecektir "123"Bu yanlış gibi görünüyor Benim.. valuegeri geliyor {name: 123..değil {name:"123"..tam olarak tüm kodu yapıştırın ve o değişikliği kopyalarken.
123yerine kullanarak "Bob").
Transformedtür tanımlamana gerek olduğunu sanmıyorum . Sadece kullanabilirsin Object. type Descriptor<T extends Object> = { ... };
TransformedTipi tamamen gereksiz. Cevabı buna göre güncelledim.
123otomatik bir dizeye dönüştürülecek "123"o JSON nesnesi bir sayı olduğundan,.
Ek olarak, Sparkson gibi json'unuzun tür doğrulamasını gerçekleştiren kitaplıkları kullanabilirsiniz . Yanıtınızı ayrıştırmak istediğiniz bir TypeScript sınıfı tanımlamanıza izin verir, sizin durumunuzda şunlar olabilir:
import { Field } from "sparkson";
class Response {
constructor(
@Field("name") public name: string,
@Field("error") public error: boolean
) {}
}
Kitaplık, gerekli alanların JSON yükünde mevcut olup olmadığını ve türlerinin doğru olup olmadığını doğrular. Ayrıca bir dizi doğrulama ve dönüştürme de yapabilir.
Bunun için harika bir kütüphane var ts-json-object
Sizin durumunuzda aşağıdaki kodu çalıştırmanız gerekir:
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});
Bu kütüphane, ayrıştırmadan önce json'u doğrular
JSON.parse TypeScript'te mevcuttur, yani sadece kullanabilirsiniz:
JSON.parse('{"name": "Bob", "error": false}') // Returns a value of type 'any'
Ancak, genellikle bir tür değeri ile uğraşmak yerine, belirli bir türle eşleştiğinden emin olurken bir JSON nesnesini ayrıştırmak isteyeceksiniz any. Bu durumda, aşağıdaki gibi bir işlev tanımlayabilirsiniz:
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;
}
Bu işlev bir JSON dizesi ve oluşturduğunuz nesnenin her alanını yükleyen ayrı işlevleri içeren bir nesne alır. Bunu şu şekilde kullanabilirsiniz:
const value = parse_json(
'{"name": "Bob", "error": false}',
{ name: String, error: Boolean, }
);
Typescript, JS'ye derlendiğinden bir JavaScript çalışma zamanına sahiptir. Gibi dilin bir parçası olarak inşa edilmiştir Bu araçlar JS nesneler JSON, Objectve MathTS de mevcuttur. Bu nedenle JSON.parse, JSON dizesini ayrıştırmak için sadece yöntemi kullanabiliriz .
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"]
Şimdi tek şey, parsedObj'nin anygenellikle TS'de kötü bir uygulama olan tür olmasıdır. Yazı korumaları kullanıyorsak nesneyi yazabiliriz. İşte bir örnek:
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
}