Возврат ответа с избыточным обещанием в одном интерфейсе в TypeScript - PullRequest
0 голосов
/ 12 января 2019

Я использую суперагент для выполнения запросов REST, которые возвращают JSON. Я хочу, чтобы эти запросы были инкапсулированы в классе, который возвращает интерфейс с результатами get или post, включая статус HTTP и ошибку. Так что вместо того, чтобы иметь отдельные обработчики для разрешения и отклонения. Я просто хочу, чтобы метод возвращал обещание с одним интерфейсом.

Например, используя https://jsonplaceholder.typicode.com/, для задачи я хочу вернуть:

export interface ITodo {
    userId: number;
    id: number;
    title: string;
    completed: boolean;
    status: number;
    ok: boolean;
    error: string;
}

и вызывающий просто делает:

    const todo: ITodo = await TodoRequest.getTodo(100);
    if (todo.ok) {
        console.log(todo.title);
    } else {
        console.log("Error status " + todo.status + " reason: " + todo.error);
    }

У меня есть следующий класс, и он хорошо работает во время выполнения, но независимо от того, что я делаю, я получаю ошибки TSLINT с моим синтаксисом, особенно со строкой res: superagent.Response:

src/actions/TodoRequest.ts:26:15 - error TS2322: Type 'ITodo | Response' is not assignable to type 'Response'.

Есть ли лучший способ закодировать это?

export class TodoRequest {

    public static async getTodo(id: number): Promise<ITodo> {
        const todo: ITodo = {} as ITodo;
        const site: string = "https://jsonplaceholder.typicode.com/";
        const query = "todos/" + id;
        const res: superagent.Response = await TodoRequest.getRequest(site + query).catch((error) => {
            if (error.message) {
                todo.error = error.message;
            }
            if (error.status) {
                todo.status = error.status;
            }
            todo.ok = false;
            return todo;
        });
        if (res.status) {
            todo.status = res.status;
        }
        if (res.ok) {
            todo.ok = res.ok;
        }
        if (res.body) {
            if (res.body.id) {
                todo.id = res.body.id;
            }
            if (res.body.userId) {
                todo.userId = res.body.userId;
            }
            if (res.body.title) {
                todo.title = res.body.title;
            }
            if (res.body.completed) {
                todo.completed = res.body.completed;
            }
            todo.ok = true;
        }
        return todo;
    }

    protected static getRequest(url: string): Promise<superagent.Response> {
        return new Promise<superagent.Response>((resolve, reject) => {
            superagent
                .get(url)
                .set("Content-Type", "application/json")
                .end((err, res) => {
                    if (!err) {
                        resolve(res);
                    } else {
                        reject(err);
                    }
                });
        });
    }


1 Ответ

0 голосов
/ 12 января 2019

Вы можете использовать Unions и Type Guards в своих определениях функций. Они определены здесь:

https://www.typescriptlang.org/docs/handbook/advanced-types.html

Это будет работать на https://www.typescriptlang.org/play/:

interface ITodo {
    Thing: string
}

interface IError {
    Status: number,
    Message: string
}

function getIt(returnTodo: boolean): Promise<ITodo | IError> {
    if (returnTodo) {
        return Promise.resolve({
            Thing: "Hi todo"
        });
    }

    return Promise.resolve({
        Status: 55,
        Message: "You said false..."
    });
}

function isError(res: IError | ITodo): res is IError {
    return (<IError>res).Status !== undefined;
}

getIt(false)
    .then((value) => {
        if (isError(value)) {
            const elem = document.createElement("p");
            elem.innerText = `Error: ${value.Message}`;
            document.body.append(elem);
        }
    });

getIt(true)
    .then((value) => {
        if (isError(value)) {
            // Won't get this...
        } else {
            const elem = document.createElement("p");
            elem.innerText = `TODO: ${value.Thing}`;
            document.body.append(elem);
        }
    });
...