Typescript:如果提供了类型,如何要求一个属性,如果不提供该类型,如何禁止该属性?

时间:2019-11-12 17:21:22

标签: typescript

我正在从快速的REST API返回数据。我想使我与客户端的API通信紧密联系。为此,我试图创建一个函数apiJsonResponse,通过该函数,我所有返回的数据都将在服务器上传输。这是到目前为止我所拥有的示例:

// Example route 1
router.get('/authorized', (req: Request, res: Response) => {
  return apiJsonResponse<{ foo: string }>(res, 200, {
    message: 'Success',
    data: { foo: 'bar' }
  });
});

// Example route 2
router.get('/unauthorized', (req: Request, res: Response) => {
  return apiJsonResponse(res, 401, {
    message: 'User is not authorized',
    isMessageDisplayable: true
  });
});

// Type-explicit wrapper around `res.status().json()`
function apiJsonResponse<T = undefined>(res: Response, status: number, body: TBody<T>): Response {
  return res.status(status).json(body);
}

// My attempt to type for a 'data-case' and a 'no-data-case'
type TBody<T> = T extends undefined ? IBody : IDataBody<T>;

interface IBody {
  message: string; // Event descriptor
  isMessageDisplayable?: boolean; // Flag whether or not to show user message
}

interface IDataBody<T> extends IBody {
  data: T; // Data payload if query is successful
}

因此,基本上,我正在尝试启用两种类型的数据响应。

情况1:无数据有效载荷。这主要用于4xx / 5xx事件,在该事件中,我返回一条消息并指出是否可显示给最终用户。

情况2。数据有效负载。主要用于返回数据有效载荷的2xx事件。

现在,我要的是让函数apiJsonResponse require body参数以包含类型为T的数据属性,前提是该函数使用该类型进行调用:{{1} }其中x满足apiJsonResponse<T>(url,{data: x, ... })。这样,我的客户端可以从这样的路由中获取数据,并期望主体包含相同类型的数据属性(从而可以使我的服务器和客户端与同一接口进行通信)。

相反,如果在未声明任何类型的情况下调用我的函数,则键入脚本将禁止在主体参数中包含数据属性。

我希望上面的代码可以解决问题,但事实并非如此。例如,以下对apiJsonResponse函数的调用未提供任何类型,在主体中包含T参数,但不会引发打字错误:

data

很显然,我对条件式打字稿的理解很缺乏。我认为通过不提供类型,该函数将采用默认的apiJsonResponse(res, 200, { message: 'Success sending basic test', data: { test: 'hello-world' }, isMessageDisplayable: true }); 值(请参见上面的undefined),并且条件语句<T = undefined>会在以下情况下返回T extends undefined ? IBody : IDataBody<T>:没有提供类型。然而,这种情况并非如此;相反,无论是否提供类型,以上代码似乎总是返回IDataBody。

对于此处发生的事情的澄清和/或解决方案将不胜感激!

1 个答案:

答案 0 :(得分:0)

好的,我找出了问题和解决方案。原始代码很接近(条件语句不是问题),但是Typescript想要在向apiJsonResponse函数提供具体值的参数时推断类型T,然后根据该推断,选择后一个接口({{ 1}})。

为防止类型推断,可以将类型逻辑基于扩展了第一个类型的第二个类型变量。以下修改为我提供了我想要的确切行为:

IDataBody<T>