У меня есть функция TypeScript, которая анализирует некоторый JSON и запускает его через средство защиты типов, чтобы убедиться, что данные действительны, чтобы остальная часть кода времени компиляции знала, что имеет дело с объектом, который фактически соответствует ожидаемому интерфейсу..
Однако мне трудно заставить TypeScript принудительно запустить защиту типов.Очевидно, JSON.parse
возвращает any
, который можно назначить любому другому типу и, следовательно, проверяет, даже если я указываю тип, отличный от any
.
const validPerson = `{"firstName": "John", "lastName": "Doe"}`;
const invalidPerson = `{"foo": 123}`;
interface Person {
firstName: string;
lastName: string;
}
interface PersonGetter {
(json: string): Person | undefined;
}
function isPerson(o: any): o is Person {
return typeof o.firstName === "string" && typeof o.lastName === "string";
}
// BAD: Type checks, but it's overly permissive. `JSON.parse` could return anything.
const getPerson1: PersonGetter = (json) => {
const o = JSON.parse(json);
return o;
}
// GOOD (kinda): Requires type guard to pass.
// `unknown` requires TS 3, which is fine in general, but bad for me.
// Also, I feel like having to remember to case the return from `JSON.parse` is a responsibility the programmer shouldn't bear.
const getPerson2: PersonGetter = (json) => {
const o: unknown = JSON.parse(json);
if (isPerson(o)) {
return o;
} else {
return undefined;
}
}
// GOOD (kinda): Requires type guard to pass. Works in TS 2.8.
// Still, not great that I have to cast the return value from `JSON.parse`, but I could probably work around that.
type JSONPrimitive = string | number | boolean | null;
type JSONValue = JSONPrimitive | JSONObject | JSONArray;
type JSONObject = { [member: string]: JSONValue };
interface JSONArray extends Array<JSONValue> {}
const getPerson3: PersonGetter = (json) => {
const o: JSONValue = JSON.parse(json);
if (isPerson(o)) {
return o;
} else {
return undefined;
}
}
TypeScript Playground link
Вариант 3 будет работать для меня, но он использует предложенные типы JSON, которые все еще обсуждаются и по-прежнему возлагает ответственность на разработчика (который может так же легко не использовать типОхрана и все еще думают, что они соблюдают интерфейс).
Может показаться, что JSON.parse
возвращение any
является источником моей проблемы здесь.Я уже работаю в режиме strict
, но может показаться, что он по-прежнему позволяет расшифровать что-то явно напечатанное как any
до явно возвращаемого типа функции.
Есть ли другой способ сказать,TypeScript, что возвращаемое значение функции должно быть типом возврата, указанным в реализуемом интерфейсе, а не any
?