带有类型提示的 TypeScript 共享配置对象

TypeScript shared configuration object with typehinting

我正在开发一个 API 库,我很好奇在 Node.js 中应该如何使用 TypeScript 处理端点配置问题。我希望所有端点配置都包含在一个实体中。

我目前采用了这种方法:

ApiConstants.ts
------------------------
const BASE_DOMAIN = 'https://api.example.com';

export default Object.freeze({
  BASE_DOMAIN: {
    V1: `${BASE_DOMAIN}/v0.1`,
    V2: `${BASE_DOMAIN}/v0.2`,
    V3: `${BASE_DOMAIN}/v0.3`,
  },

  PATH: {
    CATS: '/animals/cats',
  },
});

它完成了工作,我可以通过导入它并访问值在任何 class 中使用它。问题是我想限制函数只接受在这个对象中声明的值。当请求构造函数在传递不是该对象的一部分的值时应显示无效类型智能感知。

所需的类型看起来像这样。路径必须在 ApiConstants.PATH 对象中声明。

function makeRequest(path: ApiConstants.PATH) {
  ...
}

如何实现这种行为?

function makeRequest(path: keyof typeof ApiConstants.PATH) {
  // ...
}

See in Playground

一般来说,您可能想做类似

的事情
const ApiConstants = Object.freeze({
  BASE_DOMAIN: {
    V1: `${BASE_DOMAIN}/v0.1`,
    V2: `${BASE_DOMAIN}/v0.2`,
    V3: `${BASE_DOMAIN}/v0.3`,
  },

  PATH: {
    CATS: '/animals/cats',
  },
});
type ApiConstants = typeof ApiConstants;

export default ApiConstants;

以避免一直使用 typeof ApiConstants。请注意,这意味着 ApiConstants 既是一个值又是一个类型——Typescript 对此没有问题,并且会从上下文中知道你在做什么,但一些程序员觉得这很混乱。常见的命名约定是使用值的首字母小写字母和类型的首字母大写字母,如 const apiConstants = /*…*/;type ApiConstants = typeof apiConstants;.

另一方面,默认导出的值和类型都很方便。

您可能还想添加

export type ApiPaths = keyof ApiConstants['PATH'];

我们使用 ['PATH'] 因为我们在这里使用 type ApiConstants,而不是 value。我们仍然可以使用该值,但我们必须再次向其添加 typeof,如 keyof typeof ApiConstants.PATH.