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.parse
sonuç 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.stringify
bunun yerine kullanmanız gerekir .
Yanıtlar:
Typescript (bir üst kümesi) javascript, yani javascript'te yaptığınız JSON.parse
gibi 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?)?
MyObj
mevcut değil. SO'da
JSON.parse
JSON.parse
TS bir JS üst kümesi olduğu için kullanmaya devam edebilirsiniz . Hala bir sorun var: tür güvenliğini baltalayan JSON.parse
dö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.parse
sonra 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`
}
safeJsonParse
hızlı başarısız olmak veya dene / yakala JSON.parse
hataları 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-ts
akran bağımlılığı, işlevsel programlama stilizod
: Oldukça yeni (Repo: 2020/03/07), rekabetin bu fazla olduğu usul / nesne yönelimli dahaio-ts
typescript-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:ajv
JSON'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 Descriptor
dö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 value
bu yana, daktilo edilecek String
ve Boolean
bunlar girişi çekmek ve daktilo çıktı dönmek anlamda hem "transformatörleri" dir.
Ayrıca, value
irade aslında olması o türü. Başka bir deyişle, eğer name
gerçekten öyleyse, geçerli bir dizeye sahip olmanız 123
iç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 value
Açılır pencerenin doğru türü gösterdiğini görmek için imleci tanımın üzerine getirin ."Bob"
için 123
ve örnek yeniden çalıştırın. Konsolunuzda, ismin düzgün bir şekilde dizeye dönüştürüldüğünü göreceksiniz "123"
.name
aslında edildi 123
, bu dönüştürülecektir "123"
Bu yanlış gibi görünüyor Benim.. value
geri geliyor {name: 123..
değil {name:"123"..
tam olarak tüm kodu yapıştırın ve o değişikliği kopyalarken.
123
yerine kullanarak "Bob"
).
Transformed
tür tanımlamana gerek olduğunu sanmıyorum . Sadece kullanabilirsin Object
. type Descriptor<T extends Object> = { ... };
Transformed
Tipi tamamen gereksiz. Cevabı buna göre güncelledim.
123
otomatik 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
, Object
ve Math
TS 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 any
genellikle 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
}