ts 为函数对象属性赋值时的隐式 any 问题?

新手上路,请多包涵

本人初学 ts,不是很清楚该怎么为这个问题归纳出一个标题,请见谅。

具体问题描述

我打算自己给 koa 写一个中间件 return,具体是一个具有对象属性的函数,简要描述如下:

const RETURN_METHODS_CODES = { ok: 200, notFound: 404, /* ... */ }

const koaReturn = (statusCode: number) => (msg?: string, extras?: object) => {...}

for (const method in RETURN_METHODS_CODES) {
  koaReturn[method] = koaReturn(RETURN_METHODS_CODES[method])
  // => koaReturn.ok = koaReturn(200)
}

ctx.return = koaReturn

而在挂载到 koa 的全局 ctx 对象时需要为其指定一个类型。我想要 ts 能够自动在我扩展 RETURN_METHODS_CODES 对象时更新类型定义,因此在百度了一堆博客,翻了 handbook 里的各种定义后大杂烩出一个 ts 的定义如下:

const RETURN_METHODS_CODES = { ok: 200, notFound: 404, /* ... */ } as const

type ReturnMethods = keyof typeof RETURN_METHODS_CODES
// type ReturnMethods = "ok" | "notFound"

type ReturnSimplified = {
  [K in ReturnMethods]: (msg?: string, extras?: object) => void
}

interface Return extends ReturnSimplified {
  (code: number): (msg?: string, extras?: object) => void;
}

declare module 'koa' {
  interface DefaultContext extends DefaultContextExtends {
    return: Return
  }
}

但是 ts 却在 for 循环内报错,报错信息:

koaReturn[method] = koaReturn(RETURN_METHODS_CODES[method])
//        ^^^^^^

元素隐式具有 "any" 类型,因为类型为 "string" 的表达式不能用于索引类型 "(code: number) => (msg?: string | undefined, extras?: object | undefined) => void"。在类型 "(code: number) => (省略) => void" 上找不到具有类型为 "string" 的参数的索引签名。

去网上搜了一圈,找到了这个 stackoverflow 上的提问,尝试修改代码为:

let method: ReturnMethods
for (method in RETURN_METHODS_CODES) {
  koaReturn[method] = koaReturn(RETURN_METHODS_CODES[method])
}

依然无效,报错位置不变,信息为:

元素隐式具有 "any" 类型,因为类型为 ""ok" | "notFound"" 的表达式不能用于索引类型 "(code: number) => (msg?: string | undefined, extras?: object | undefined) => void"。类型“(code: number) => (省略) => void”上不存在属性“ok”。

在此请问各位大佬,这个类型注解应该如何正确书写?还是我应该尝试换一种更方便于写注解的函数?已经摆烂到想写个 any 上去了

阅读 4.2k
4 个回答

你修改后的写法是没有问题的,是否忘记指定 koaReturn 类型为 Return ?

const koaReturn = ((statusCode) => (msg, extras) => {}) as Return

let method: ReturnMethods
for (method in RETURN_METHODS_CODES) {
  koaReturn[method] = koaReturn(RETURN_METHODS_CODES[method]) // ok
}

另一种写法

Object.entries(RETURN_METHODS_CODES)
  .forEach(([method, code]) => koaReturn[method as ReturnMethods] = koaReturn(code))

试试这个

const RETURN_METHODS_CODES: Record<string, number> = { ok: 200, notFound: 404, /* ... */ }

ctx.return = {} as any;
let method: ReturnMethods
for (method in RETURN_METHODS_CODES) {
ctx.return[method] = koaReturn(RETURN_METHODS_CODES[method])
}

把你的箭头函数变为常规函数

function koaReturn (statusCode: number) {
  return function (msg?: string, extras?: object) {
    return '....'
  }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
logo
Microsoft
子站问答
访问
宣传栏