Czy istnieje sposób na analizowanie ciągów jako JSON w Typescript.
Przykład: W JS możemy użyć JSON.parse(). Czy w Typescript jest podobna funkcja?
Mam ciąg obiektu JSON w następujący sposób:
{"name": "Bob", "error": false}
Czy istnieje sposób na analizowanie ciągów jako JSON w Typescript.
Przykład: W JS możemy użyć JSON.parse(). Czy w Typescript jest podobna funkcja?
Mam ciąg obiektu JSON w następujący sposób:
{"name": "Bob", "error": false}
JSON.parse, otrzymujesz obiekt jako wynik, a nie string(zobacz moją odpowiedź po więcej). Jeśli chcesz zamienić obiekt w ciąg, musisz użyć JSON.stringifyzamiast tego.
Odpowiedzi:
Maszynopis to (nadzbiór) javascript, więc używasz go tak, JSON.parsejak w javascript:
let obj = JSON.parse(jsonString);
Tyle tylko, że w maszynopisie możesz mieć typ do wynikowego obiektu:
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 }'przez '{ "myString": "string", "myNumberBAD": 4 }'nie zakończy się niepowodzeniem, a obj.myNumber zwróci wartość undefined.
Json.parse(text).validate[MyObj]. playframework.com/documentation/2.6.x/ScalaJson jak możesz zrobić to samo w maszynie (może jest do tego zewnętrzna biblioteka?)?
MyObjnie istnieje. W SO jest wiele innych wątków na ten temat, na przykład: Sprawdź, czy obiekt implementuje interfejs w czasie wykonywania z TypeScript
JSON.parseMożesz nadal używać JSON.parse, ponieważ TS to nadzbiór JS. Nadal pozostaje problem: JSON.parsezwraca any, co podważa bezpieczeństwo typów. Oto dwie opcje dla silniejszych typów:
Zabezpieczenia typu niestandardowego są najprostszym rozwiązaniem i często wystarczają do weryfikacji danych zewnętrznych:
// 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
}
Opakowanie JSON.parsemoże następnie przyjąć typ ochrony jako dane wejściowe i zwrócić przeanalizowaną, wpisaną wartość:
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 }
Przykład użycia:
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`
}
safeJsonParsemoże zostać przedłużony, aby szybko zawieść lub spróbować / złapać JSON.parsebłędy.
Ręczne pisanie funkcji ochrony typów staje się uciążliwe, jeśli trzeba zweryfikować wiele różnych wartości. Istnieją biblioteki, które mogą pomóc w tym zadaniu - przykłady (brak pełnej listy):
io-ts: rel. popularny (obecnie 3,2 tys. gwiazdek), fp-tszależność od rówieśników, funkcjonalny styl programowaniazod: całkiem nowy (repo: 2020-03-07), stara się być bardziej proceduralny / obiektowy niżio-tstypescript-isTransformator TS do kompilatora API dodatkowe owinięcie jak ttypescript potrzebnetypescript-json-schema/ ajv: Utwórz schemat JSON z typów i zweryfikuj go za pomocąajvJeśli chcesz, aby twój JSON miał zweryfikowany typ skryptu, musisz sam wykonać tę walidację. To nic nowego. W zwykłym JavaScript musisz zrobić to samo.
Lubię wyrażać swoją logikę walidacji jako zbiór „transformacji”. Definiuję a Descriptorjako mapę przekształceń:
type Descriptor<T> = {
[P in keyof T]: (v: any) => T[P];
};
Następnie mogę utworzyć funkcję, która zastosuje te przekształcenia do dowolnego wejścia:
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;
}
Teraz nie tylko sprawdzam poprawność danych wejściowych JSON, ale buduję typ Typescript na bieżąco. Powyższe typy ogólne zapewniają, że wynik wywnioskuje typy z Twoich „przekształceń”.
W przypadku, gdy transformacja zgłasza błąd (tak jak zaimplementowałbyś walidację), chciałbym owinąć go innym błędem pokazującym, który klucz spowodował błąd.
W twoim przykładzie użyłbym tego w następujący sposób:
const value = pick(JSON.parse('{"name": "Bob", "error": false}'), {
name: String,
error: Boolean,
});
Teraz valuezostaną wpisane, ponieważ Stringi Booleanto zarówno „Transformers” w sensie podejmowania wejście i powrót wpisywanych wyjście.
Co więcej, valuetestament faktycznie będzie tego typu. Innymi słowy, jeśli namefaktycznie tak było 123, zostanie przekształcone w "123", aby uzyskać prawidłowy ciąg. Dzieje się tak, ponieważ Stringw czasie wykonywania używaliśmy wbudowanej funkcji, która akceptuje dowolne dane wejściowe i zwraca plik string.
Możesz zobaczyć, jak to działa tutaj . Spróbuj następujących rzeczy, aby się przekonać:
const valuedefinicję, aby zobaczyć, że wyskakujące okienko pokazuje prawidłowy typ."Bob"się 123i ponownie uruchomić próbki. W konsoli zobaczysz, że nazwa została poprawnie przekonwertowana na ciąg "123".namefaktycznie był 123, zostanie przekształcony na "123". Wydaje się, że jest to niepoprawne. Mój valuewraca {name: 123..nie, {name:"123"..kiedy
123zamiast "Bob").
Transformedtyp. Możesz po prostu użyć Object. type Descriptor<T extends Object> = { ... };
TransformedTyp jest całkowicie zbędne. Odpowiednio zaktualizowałem odpowiedź.
123aby był on automatycznie konwertowany na ciąg "123", ponieważ jest to liczba w obiekcie JSON.
Możesz dodatkowo użyć bibliotek, które wykonują sprawdzanie poprawności typu json, takich jak Sparkson . Pozwalają zdefiniować klasę TypeScript, do której chcesz przeanalizować swoją odpowiedź, w twoim przypadku może to być:
import { Field } from "sparkson";
class Response {
constructor(
@Field("name") public name: string,
@Field("error") public error: boolean
) {}
}
Biblioteka sprawdzi, czy wymagane pola znajdują się w ładunku JSON i czy ich typy są poprawne. Może również przeprowadzić szereg weryfikacji i konwersji.
Jest do tego świetna biblioteka ts-json-object
W twoim przypadku musisz uruchomić następujący kod:
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});
Ta biblioteka sprawdzi poprawność pliku json przed analizowaniem
JSON.parse jest dostępny w języku TypeScript, więc możesz go po prostu użyć:
JSON.parse('{"name": "Bob", "error": false}') // Returns a value of type 'any'
Jednak często będziesz chciał przeanalizować obiekt JSON, upewniając się, że pasuje do określonego typu, zamiast zajmować się wartością typu any. W takim przypadku możesz zdefiniować funkcję, taką jak:
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;
}
Ta funkcja przyjmuje ciąg JSON i obiekt zawierający indywidualne funkcje, które ładują każde pole tworzonego obiektu. Możesz go używać w ten sposób:
const value = parse_json(
'{"name": "Bob", "error": false}',
{ name: String, error: Boolean, }
);