首页 > 解决方案 > 如何检查字符串以将其缩小到枚举中的字符串,并让 TypeScript 识别它(节点示例)?

问题描述

使用基本的 node.js,在http.createServer我接受request, 并path从请求中接受。我有一个router以路径为键的对象,其值是处理函数。

// index.ts

export interface DataObject {
  queryStringObject: ParsedUrlQuery;
  method: string;
  headers: IncomingHttpHeaders;
  payload: any;
}

export type HandlerCallback = (statusCode: number, payload?: Object) => any;

export type Handler = (data: DataObject, callback: HandlerCallback) => any;

interface Router {
  ping: Handler;
  users: Handler;
  adminUsers: Handler;
  tokens: Handler;
}

// Define request router
const router: Router = {
  ping: handlers.ping,
  users: handlers.users,
  adminUsers: handlers.adminUsers,
  tokens: handlers.tokens,
};

export enum RestMethods {
  get = 'get',
  post = 'post',
  put = 'put',
  delete = 'delete',
}

export type RestHandler = {
  [method in RestMethods]: Handler;
};

然后,我有handlers定义的文件:

interface Handlers {
  users: Handler;
  adminUsers: Handler;
  tokens: Handler;
  notFound: Handler;
  ping: Handler;
}

interface SubHandlers {
  users: RestHandler;
  adminUsers: RestHandler;
  tokens: RestHandler;
}

export const handlers: Handlers = {
  users: (data, callback) => {
    const acceptableMethods = ['get', 'post', 'put', 'delete'];
    if (acceptableMethods.indexOf(data.method) !== -1) {
      subHandlers.users[data.method](data, callback);
    }
  },
(...)

我在线上遇到typescript错误subhandlers.users[data.method]...

错误:(62, 14) TS7053:元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型“路由器”。在“路由器”类型上找不到具有“字符串”类型参数的索引签名。

data.method是 astring因为DataObject以这种方式定义它(传入的请求可能包含任何内容method),并且subhandlers.users是 type RestHandler,它是一个在 enum 中具有键的对象RestMethods。但我正在检查acceptableMethods.indexOf(data.method) !== -1......我怎样才能进行这个检查,以便 Typescript 可以意识到 data.method 仅限于枚举中的字符串?

标签: node.jstypescript

解决方案


这里有两个问题;一种是acceptableMethods推断为 type string[],而您希望编译器跟踪它包含的字符串文字值;您可以使用以下const断言轻松解决该问题:

const acceptableMethods = ["get", "post", "put", "delete"] as const;

第二个问题是 TypeScript 不理解或不期望,给定一个arraytypeT[]和一个 value的数组val,检查array.indexOf(val) !== -1应该缩小val到 type T。幸运的是,您可以通过创建用户定义的类型保护函数来获得这种行为:

function arrayIncludes<T>(
  arr: ReadonlyArray<T>,
  val: any
): val is T {
  return arr.indexOf(val) !== -1;
}

现在您可以使用arrayIncludes()代替indexOf支票,它应该适合您:

export const handlers: Handlers = {
  users: (data, callback) => {
    const acceptableMethods = ["get", "post", "put", "delete"] as const;
    if (arrayIncludes(acceptableMethods, data.method)) {
      subHandlers.users[data.method](data, callback); // okay
    }
  }
};

这有帮助吗?祝你好运!

链接到代码


推荐阅读