【问题标题】:Is it possible to contrain inferred generics in typescript?是否可以在打字稿中限制推断的泛型?
【发布时间】:2021-11-16 11:47:01
【问题描述】:

举个例子:

type A<Keys extends string, Prefix extends string> = 
  {[K in Keys]: `${Prefix}-${K}`}

function noGood<K extends string, Prefix extends string>(
  obj: A<K, Prefix>, prefix: Prefix
) {
// ...
}

const test: A<'one' | 'two', 'prefix'> = {"one": 'prefix-one', "two": 'prefix-two'}

noGood(test, 'desired to only be "prefix", but can be any string...')

您可以看到 noGood 的泛型类型是从第一个参数 (obj) 推断出来的。然后,当您向第二个参数提供字符串时 (prefix)

显然,您可以输入您对noGood 的调用,它会禁止第二个参数使用该随机字符串,但理想情况下您不必这样做。

编辑: 问题不清楚。

澄清一下,问题是当您推断noGood 的参数时,Prefix 推断无法按预期工作(但不一定是意外),因为将Prefix 约束到obj 的通用 Prefix(第一个参数)。

在此示例中,Prefix(通用)实际上是 'prefix',并且希望只允许 noGood 推断出的第二个参数。但是,当您调用 noGood(obj, 'diff-prefix') 时,Prefix 泛型变为 'prefix' | 'diff-prefix',理想情况下,它将被限制为从 obj 推断的类型,而不是从第一个和第二个参数的并集推断的类型。

希望能解决问题。肯定可以看出它是如何不清楚的。

【问题讨论】:

  • 我不明白; desired to only be "one" or "two", but... 是否意味着您要支持 noGood(test, "one")?如果是这样,那为什么输入Prefix 而不是K like this?如果不是,那为什么那个字符串会这样说?这里有错字吗?我糊涂了;帮助!
  • @jcalz,对不起,这是我的错。它应该是“prefix-one”或“prefix-two”,而不仅仅是“one”或“two”。
  • 那你为什么输入Prefix而不是`${Prefix}-${K}`like this?你能说清楚这里发生了什么吗?

标签: typescript generics typescript-generics


【解决方案1】:

如果您不太关心约束“noGood()”的对象参数,这在基本层面上是微不足道的。使用泛型强制参数prefix 是对象参数obj 的键(“前缀”一词在这里似乎用词不当,因为您似乎只关心obj 的键,但我离题了):

function noGood<O extends{}>(
  obj: O, prefix: keyof O
) {
// ...
}

据我所知,没有一种方法可以从您的类型 A 中提取“Prefix”的类型信息,因为在实例化它之后,该对象不会保留该泛型类型信息——只有无法强制以obj 传入的对象绝对是您的A 类型的实例。

【讨论】:

  • 对不起,我在上面打错了。它应该是“prefix-one”或“prefix-two”,前缀和键的组合,而不仅仅是键。正如你所说的那样,肯定是一个微不足道的解决方案。
【解决方案2】:

@HelloWorld 根据您对我的另一个答案的评论,如果您希望参数 prefix 仅是对象的一个​​键处的值,则通过一些调整仍然相对容易:

const foo = {"one": 'prefix-one' as const, "two": 'prefix-two' as const}

function noGood<O extends {}>(
  obj: O, prefix: O[keyof O]
) {
// ...
}

noGood(foo, 'prefix-one'); // sure ok
noGood(foo, 'crabapple'); // error!

注意在foo 中定义值时使用as const。这很重要,因为它告诉 TypeScript 这些值不会改变,并且可以被视为常量、显式类型,而不仅仅是任何旧的string。否则,noGood(foo, 'crabapple') 不会给出错误,因为 TypeScript 通常会将foo 的每个键的值推断为string 而不是"prefix-one" | "prefix-two"

如果这仍然不符合您的用例,请更新您的问题,提供更具体的详细信息和要求。

【讨论】:

  • 再次,对不起,我问的问题很糟糕,并给出了错误的例子(两次......)。我做了一个更大的编辑,这应该让一切都清楚了。它应该只是“前缀”而不是对象的键。
  • @HelloWorld 您尝试做的事情实际上不可能仅使用 TypeScript 推断类型。您可以通过显式将类型传递给noGood() 的泛型来轻松地做到这一点,甚至无需更改您的示例代码:noGood&lt;keyof typeof test, 'prefix'&gt;(test, 'desired to only be "prefix", but can be any string...'); // will now error。但这有点违背了目的,因为您必须明确地将 "prefix" 传递给泛型,如果您已经这样做了,那么您只是在重复自己。
  • 感谢@jered。是的,希望有一些其他的约束可能隐含地推断出类型。我没有使用 infer 类型,并且不确定这是否会以某种我无法从示例中确定的方式来解决问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-10
  • 2020-12-17
  • 2022-11-23
  • 2021-09-29
  • 1970-01-01
  • 2020-06-08
  • 2016-10-19
相关资源
最近更新 更多