[英]In Typescript, how do I infer the keyof indexed access type used in a template literal
我有一个 REST api 接口,如下所示:
interface APIs {
artist: {
POST: { req: TypeA, resp: TypeB}
DELETE: { req: TypeC, resp: TypeD },
}
location: {
GET: { req: TypeE, resp: TypeF }
}
}
我想转换为一组这样的函数:
const server: Server<APIs> = {
postArtist: (req: TypeA) => TypeB,
deleteArtist: (req: TypeC) => TypeD,
getLocation: (req: TypeE) => TypeF,
}
我已经设法创建几乎创建一个Server<T>
类型但是我无法引用POST
| DELETE
| 模板文字中使用的GET
键。 它们在下面显示为key of T[Key]
,因此可以在右侧使用?
是。
type Server<T> = {
[Key in keyof T as `${Lowercase<keyof T[Key] & string>}${Capitalize<Key & string>}`]: (req: T[Key][?]) => void
}
// |^=How to get this=^| and use it here -^^
如何引用用于生成 function 名称的密钥,以便我可以在右侧引用它。
目前在${Lowercase<keyof T[Key] & string>}${Capitalize<Key & string>}
中, keyof T[Key]
会是一个并集,所以类型表达式会生成一个键的并集,导致所有结果中预设了子键。 如果我们只需要子键,这是一个很好的方法。
如果我们需要单独处理每个子属性,尽管我们应该使用另一个映射类型来单独生成每个 function,然后将它们合并回结果中。 要将它们合并回单个 object 我们可以从这里使用UnionToIntersection
要提取请求和响应类型,最简单的解决方案是使用条件类型:
interface RequestDefinition<TReq, TResp> {
req: TReq,
resp: TResp
}
type FromDefinition<T> =
T extends RequestDefinition<infer TReq, infer TResp>? (req: TReq) => TResp: never
type UnionToIntersection<U> =
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
type Server<T> = UnionToIntersection<{
[Key in keyof T]: {
[Http in keyof T[Key] as `${Lowercase<Http & string>}${Capitalize<Key & string>}`]: FromDefinition<T[Key][Http]>
}
}[keyof T]>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.