typescript 依赖于第一个参数的参数

kb5ga3dv  于 2023-03-13  发布在  TypeScript
关注(0)|答案(3)|浏览(190)

我正在编写一个简单的泛型函数,如下所示:

function x<T>(a: T[], b: T) {
  return ''
}

x(['hello', 'world'], 'world')

我希望用户在第一个参数中输入一个字符串数组,例如:

['red', 'yellow', 'green']

我希望第二个参数的类型为string,并且它必须是前一个参数中提供的值之一,因此代码编辑器应该显示以下选项的自动完成:

  • 红色
  • 黄色
  • 绿色

如果用户试图编写这些以外的代码,代码编辑器(或者说编译器)应该显示错误。
实现这一目标的最佳途径是什么?

wecizke3

wecizke31#

可以通过创建扩展第一个泛型参数的第二个泛型参数来强制推理的方向。

function x<T extends string, U extends T>(a: T[], b: U) {
  return ''
}

x(['hello', 'world'], 'hello') // fine

x(['hello', 'world'], 'nope')
// Argument of type '"nope"' is not assignable to parameter of type
//   '"hello" | "world"'.(2345)

注意,T需要一个约束,如T extends string。没有它,T被推断为string,而不是任何字符串类型。添加string约束似乎迫使编译器认为它可能是string的子类型。
见Playground
您也可以关闭该约束,并传递数组as const,如下所示:

function x<T, U extends T>(a: readonly T[], b: U) {
  return ''
}

x(['hello', 'world'] as const, 'hello') // fine

x(['hello', 'world'] as const, 'nope')
// Argument of type '"nope"' is not assignable to parameter of type '"hello" | "world"'.(2345)

见Playground
或者,如果您使用的是Typescript 5.0,则const使用const泛型类型,以告诉typescript默认情况下推断为const。

function x<const T, U extends T>(a: T[], b: U) {
  return ''
}

x(['hello', 'world'], 'hello') // fine

x(['hello', 'world'], 'nope')
// Argument of type '"nope"' is not assignable to parameter of type '"hello" | "world"'.(2345)

见Playground
所有这些选项看起来都很适合自动完成:

vktxenjb

vktxenjb2#

这很可能是不可能的。您的函数在运行时可能会接收不同的输入,因此不可能知道代码在编译时(TypeScript检查您的类型)将如何运行。例如,如果我传递了一个随机生成的数组,那么编译器如何知道一个值是否会在随机生成的数组中?
与输入不同,看起来您希望执行输入验证,即在运行时检查输入。在您的情况下,这真的很容易:

function x<T>(a: T[], b: T) {
    if (!a.includes(b)) throw new Error('"b" is not in array "a"');
}

x(['hello', 'world'], 'world')
x(['hello', 'world'], '1')
h5qlskok

h5qlskok3#

如果用户愿意将as const附加到a值,则以下代码对我有效:

function x<T>(a: readonly T[], b: typeof a[number]) {}

x(['red', 'green', 'blue'] as const, 'green')

这样,我的VSCode编辑器就为b的自动完成提供了a的值(没有readonlyas constT通常被推断为string)。
但是我发现我仍然可以为b输入其他string值而不会出错,所以编译器似乎没有强制执行这一点,相反,它默默地扩展了T联合类型以容纳为b给定的任何值。
我使用的是VSCode、Angular Language Service和TypeScript 4.9。

相关问题