Типизированный REST API с вложенными схемами - PullRequest
0 голосов
/ 20 апреля 2019

Я экспериментирую с Typescript, чтобы написать полный типизированный код, который выполняет запросы к существующему API REST.Этот API позволяет произвольное вложение моделей в запрос.Для простоты, скажем, у нас есть только две модели User и Address и подделка getUser.Вот что я получил:

interface User {
    id: string;
    name: string;
    age: number;
    address: Address;
}

interface Address {
    country: string;
    city: string;
}

type UserSelector = {
    id: null;
    name: null;
    age: null;
    address: Partial<AddressSelector>;
};

type AddressSelector = {
    country: null;
    city: null;
};

function getUser<K extends keyof UserSelector>(_fields: Pick<UserSelector, K>): Pick<User, K> {
    // return a mock object, will get from DB in real code
    return {
        id: "1",
        name: "Jean Seberg",
        age: 30,
        address: { country: "FR", city: "Paris" },
    } as Pick<User, K>;
}

const user = getUser({
    //unknownField: null, // SHOULD TYPE ERROR, IT DOES
    id: null,
    age: null,
    address: { country: null },
});

console.log(user.id, user.age, user.address.country);
//console.log(user.name); // SHOULD TYPE ERROR, IT DOES
console.log(user.address.city); // SHOULD TYPE ERROR, IT DOES NOT

Как видите, это работает не так, как ожидалось, user.address.city должно выдавать ошибку типа компиляции, потому что ключ city отсутствует в селекторе адресов.Понятно, почему это не работает, но я не знаю, как писать универсальным образом, чтобы он поддерживал любой уровень вложенности (жесткое кодирование типов с отношениями не представляется возможным).

Возможно ли это вМашинопись (любая версия).Как?

1 Ответ

0 голосов
/ 20 апреля 2019

Проверка типа верна.

type UserSelector = {
    id: null;
    name: null;
    age: null;
    address: Partial<AddressSelector>;
};

type AddressSelector = {
    country: null;
    city: null;
};

свойство address из UserSelector равно Partial ,, что означает, что все свойства AddressSelector являются необязательными, поэтому все в порядке, если cityне отображается.

По вашему желанию вы должны удалить Partial и указать тип AddressSelector ['country'] и AddressSelector ['city'].

...