简体   繁体   English

Typescript 可选默认值参数的通用类型

[英]Typescript generic type for optional default value argument

I am new to Typescript and I am running into an issue with Generic types.我是 Typescript 的新手,我遇到了通用类型的问题。 I am creating a library that reads our configuration.我正在创建一个库来读取我们的配置。 Due to our configuration being arbitrary JSON we are using the any type.由于我们的配置是任意的 JSON 我们使用的是 any 类型。 However when a consumer uses this library they should know the shape of the data they expect and I want to make a function for retrieving information from the config that we can pass a type to remove the any type from the chain.然而,当消费者使用这个库时,他们应该知道他们期望的数据的形状,我想制作一个 function 来从配置中检索信息,我们可以传递一个类型以从链中删除任何类型。 Additionally I want this function that retrieves the value from the config to take an optional argument that will be the default value returned if the key is missing from the config.此外,我希望这个从配置中检索值的 function 接受一个可选参数,如果配置中缺少密钥,该参数将作为返回的默认值。 My problem is figuring out how to properly type this function so that the function's return type is either the type we pass in as a generic or the type of the default value while taking into account we may omit the default value argument entirely.我的问题是弄清楚如何正确键入此 function,以便函数的返回类型是我们作为泛型传入的类型或默认值的类型,同时考虑到我们可能会完全省略默认值参数。

I have boiled down my use case to this really simple example.我已将我的用例归结为这个非常简单的示例。

/* Our config provider module */

//In our real use, config is loaded from a JSON file that can be an arbitrary shape so we must use any type here
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const config: Record<string, any> = {
  'mode': 'alpha'
}

const getConfig = <Result, DefaultValue extends Result | undefined = undefined>(key: string, defaultValue?: DefaultValue): Result | DefaultValue => {
  const result = config[key] as Result
  return result ?? defaultValue
}

/* In another module */
// The consumer of the config knows what shape they are going to read so we want to break the `any` usage here:

// mode should be of type string | undefined since a default value was not provided
const mode = getConfig<string>('mode')

// mode2 should be of type string | string (or just string) since a default value was provided
const mode2 = getConfig<string>('mode', 'omega')

This example doesn't compile and I get the error:这个例子没有编译,我得到了错误:

Type 'Result |输入“结果 | DefaultValue |默认值 | undefined' is not assignable to type 'Result | undefined' 不可分配给类型 'Result | DefaultValue'.默认值'。 Type 'undefined' is not assignable to type 'Result |类型“undefined”不可分配给类型“Result | DefaultValue'.ts(2322)默认值'.ts(2322)

Any advice on how I can properly type my getConfig function so that if I pass in a type for the Result and the function will properly infer the type of the defaultValue argument (including undefined ) and use that as part of it's return type, while also maintaining that if we do pass an actual value for the defaultValue then the type does not have undefined ?关于如何正确键入getConfig function 的任何建议,以便如果我为结果传递类型,function 将正确推断defaultValue参数的类型(包括undefined )并将其用作返回类型的一部分,同时维护如果我们确实为defaultValue传递了一个实际值,那么该类型没有undefined

Note: I am aware that what I want will not actually validate the contents of the JSON data structure and will compile just fine but if when parsing the JSON the value doesn't match what we pass in as the generic type it could break at runtime.注意:我知道我想要的实际上不会验证 JSON 数据结构的内容并且编译得很好但是如果在解析 JSON 时该值与我们作为通用类型传入的值不匹配它可能会在运行时中断. We will aim to validate the JSON later using a schema or something.我们的目标是稍后使用模式或其他方式验证 JSON。 For now I just want to figure out how to type this properly.现在我只想弄清楚如何正确输入它。

What you appear to be saying is that the return value is either the value from the config , or the defaultValue .您似乎要说的是返回值是来自config的值或defaultValue Because defaultValue is optional, this means that return result?? defaultValue因为defaultValue是可选的,这意味着return result?? defaultValue return result?? defaultValue also includes the possibility of undefined . return result?? defaultValue还包括undefined的可能性。

If you want undefined to be a possible (in the case that its missing from config AND defaultValue is not specified, then the return type must also include undefined .如果您希望undefined成为可能(如果未指定config AND defaultValue中缺少它,则返回类型还必须包括undefined

If you want the return value to always be a value, and you aren't supplying one with defaultValue , then you need a type guard to prevent the possibility of undefined being returned, with a throw (which makes the return type effectively T | never .如果您希望返回值始终是一个值,并且您没有提供一个值defaultValue ,那么您需要一个类型保护来防止返回undefined的可能性,并抛出(这使得返回类型有效T | never .

It also appears that its not necessary to include the type assertion on config[key] to narrow from any to T , as that's implied by the return type.似乎也没有必要在config[key]上包含类型断言以从any缩小到T ,因为返回类型暗示了这一点。

const getConfig = <T>(key: string, defaultValue?: T): T => {
  const result = config[key] ?? defaultValue
  if (result === undefined) {
    throw "Can't be undefined without a default value"
  }
  return result
}

Playground Link 游乐场链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM