node.js - 如何检查字符串以将其缩小到枚举中的字符串,并让 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 仅限于枚举中的字符串?
解决方案
这里有两个问题;一种是acceptableMethods
推断为 type string[]
,而您希望编译器跟踪它包含的字符串文字值;您可以使用以下const
断言轻松解决该问题:
const acceptableMethods = ["get", "post", "put", "delete"] as const;
第二个问题是 TypeScript 不理解或不期望,给定一个array
typeT[]
和一个 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
}
}
};
这有帮助吗?祝你好运!
推荐阅读
- javascript - 当我选择一个复选框时,如何禁用 ngfor 中的所有其他复选框?
- php - Isset 不等于多个变量
- regex - 使用字段模式使用 awk 处理非常见 csv 文件
- bash - 如何将 grep 与变量和通配符一起使用?
- php - Laravel 7 中未定义的变量
- django - django-allauth 帐户模板中的 CSS 定义
- c++ - 在 find_if 中使用正向和反向迭代器有什么区别
- angular - mat-select does not display value when doing two way binding in reactive from
- proxy - Conda keeps trying to connect to a proxy even though it should be desabled
- java - Correct way of field initialisation in static code block in Java