更改有效负载的类型

时间:2017-06-07 19:00:58

标签: javascript typescript typescript-typings

我为我的Http模块创建了以下类型:

export type HttpPromise<TData> = Promise<HttpPromiseSuccess<TData>>
export type HttpPromiseSuccess<TData> = {
    config: object;
    headers: object;
    request: XMLHttpRequest;
    status: number;
    statusText: string;
    data: TData;
}

假设我有以下两种类型:

export type User = {
    id: number;
    name: string;
    ...
}
export type ApiError = {
    error: string;
    statusCode: number;
}

我通常会这样做:

const promise: HttpPromise<User> = Http.get('/api/users/1');
promise
   .then(response => {
      // response.data is now of type `User`    
   });

但我的API实际上可以返回错误类型ApiError,因此我希望response.data属于User类型或ApiError类型。我试过了

const promise: HttpPromise<User | ApiError> = Http.get('/api/users/1');
// But now response.data only contains the union of the two type

我也试过

const promise: HttpPromise<User> = Http.get('/api/users/1');
promise
   .then(response => {
       if ('error' in response.data) {
           const payload = response.data as ApiError;
       }
   });

但这不能做铸造。我有什么选择?不幸的是我无法控制API; API将始终返回200,但如果有效内容包含error,那么它将包含包含代码的statusCode

1 个答案:

答案 0 :(得分:2)

您可以使用user defined typeguard

打字机本身如下:

const isError = <T>(response: T | ApiError): response is ApiError => {
    return !!(response as ApiError).data.error;
};

这将返回一个布尔值 - 如果响应是错误则为true,否则返回false。您的请求处理程序可以是:

const promise: HttpPromise<User | ApiError> = Http.get('/api/users/1');
promise
    .then(response => {
        if (isError(response)) {
            // response typed as ApiError  
        } else {
            // response typed as User
        }
    });

因为typeguard是通用的,所以这也适用于其他响应类型:

const promise: HttpPromise<BlogPost | ApiError> = Http.get('/api/users/1');
promise
    .then(response => {
        if (isError(response)) {
            // response typed as ApiError  
        } else {
            // response typed as BlogPost
        }
    });