打字稿使用 get<T>(key: keyof T): T[key] --- 返回类型是 T 上的属性类型,而不是 T[keyof T]

时间:2021-04-25 13:48:11

标签: typescript typescript-typings typescript-generics

我已经关注了这两个在 stackoverflow [1][2] 上类似的问题,以及其他一些问题,但它们都没有真正解决我所关心的特定用例和问题所以我决定提出一个新问题。

我的用例:

  • 我有一个“getConfig”函数。
  • 我有几个配置类,例如“AppConfig”和“UsersConfig”
  • 所有配置类都有带有显式类型定义的唯一键。
  • 我希望 getConfig 的使用者提供 getConfig<T extends AppConfig | UsersConfig>(key: keyof T)
  • 我不想也将 Config 类作为输入参数传递。

我的问题:

  • 我无法构造以配置类中的实际类型为目标的类型,例如:
class AppConfig {
app_name: string = "Application Name"
}
class UsersConfig{
max_users: number = 5
}

getConfig<AppConfig>("app_name"): typeof AppConfig["app_name"] // I want this to be string
getConfig<UsersConfig>("max_users"): typeof UsersConfig["max_users"] // I want this to be number
getConfig("app_name") // I'd like this to throw, doesn't
getconfig<AppConfig>("max_users") // throws which is good

上面两个调用的响应类型当然是错误的,没有通过编译器。 我一直在研究打字稿中的条件和重载有一段时间并在小组中询问,但我仍然没有设法设计一个可行的解决方案。

附带问题:

  • 目前,如果消费者调用 getConfig("something") 并且不提供泛型,编译器不会说任何内容并且功能在整个应用程序中默默地失败,有没有办法防止这种情况?

我最接近的是 : T[keyof T],它根据 T 的所有键的类型创建了一个联合类型,这对我的目的不起作用。

谢谢。

1 个答案:

答案 0 :(得分:1)

为了能够根据提供的键推断属性类型,我们需要为键引入泛型类型参数。当前部分 type inference is not supported,因此为了能够明确指定配置类型但推断密钥类型 - 可以使用柯里化:

class AppConfig {
  app_name: string = "Application Name"
}
class UsersConfig {
  max_users: number = 5
}

declare function getConfig<T extends AppConfig | UsersConfig>(): <K extends keyof T>(key: K) => T[K]

const appName = getConfig<AppConfig>()("app_name") // string
const maxUser = getConfig<UsersConfig>()("max_users") // number
getConfig()("app_name") // throws

Playground