[英]In Typescript, how do I infer the keyof indexed access type used in a template literal
I have a REST api interface like this:我有一个 REST api 接口,如下所示:
interface APIs {
artist: {
POST: { req: TypeA, resp: TypeB}
DELETE: { req: TypeC, resp: TypeD },
}
location: {
GET: { req: TypeE, resp: TypeF }
}
}
That I want to convert to a set of functions like this:我想转换为一组这样的函数:
const server: Server<APIs> = {
postArtist: (req: TypeA) => TypeB,
deleteArtist: (req: TypeC) => TypeD,
getLocation: (req: TypeE) => TypeF,
}
I have managed to create almost create a Server<T>
type however I'm not able to reference the POST
|我已经设法创建几乎创建一个Server<T>
类型但是我无法引用POST
| DELETE
| DELETE
| GET
keys used in the template literal.模板文字中使用的GET
键。 They appear as the key of T[Key]
below so that it can be used on the right side where the ?
它们在下面显示为key of T[Key]
,因此可以在右侧使用?
is.是。
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 -^^
How do I reference the key that was used to generate the function name so that I can reference it on the right side.如何引用用于生成 function 名称的密钥,以便我可以在右侧引用它。
Currently in ${Lowercase<keyof T[Key] & string>}${Capitalize<Key & string>}
, keyof T[Key]
will be a union, and so the type expression will generate a union of keys, resulting in all sub keys being preset in the result.目前在${Lowercase<keyof T[Key] & string>}${Capitalize<Key & string>}
中, keyof T[Key]
会是一个并集,所以类型表达式会生成一个键的并集,导致所有结果中预设了子键。 This is a good approach if we just need the subkeys.如果我们只需要子键,这是一个很好的方法。
If we need to process each sub property individually though we should use another mapped type to produce each function individually and then merge them back into the result.如果我们需要单独处理每个子属性,尽管我们应该使用另一个映射类型来单独生成每个 function,然后将它们合并回结果中。 To merge them back into a single object we can use UnionToIntersection
from here要将它们合并回单个 object 我们可以从这里使用UnionToIntersection
To extract the request and response types, the simplest solution would be to use a conditional type:要提取请求和响应类型,最简单的解决方案是使用条件类型:
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.