【问题标题】:inferring a union type from a functions parameters从函数参数推断联合类型
【发布时间】:2022-01-07 01:37:13
【问题描述】:

在 Typescript 中,当我检查变量时,然后分支会根据条件推断变量类型:

type MyType = 'val1' | 'val2' | 'val3'

const variable = 'val1' as MyType

if (variable === 'val2' || variable === 'val3') {
    // typeof variable == 'val2' | 'val3'
}

上面的代码很啰嗦,尤其是当我检查两个以上的值并且我想用它替换它时

if (hasOneOf(variable, 'val2', 'val3')) {
    // typeof variable == 'val2' | 'val3'
}

我部分满意的解决方案是:

const hasOneOf = <T, U extends T>(value: T | undefined, ...values: U[]): value is U => value !== undefined && values.indexOf(value as U) >= 0

但是只有当我明确定义类型时它才有效


if (hasOneOf(variable, 'val2', 'val3')) {
    // typeof variable == MyType
}

// vs

if (hasOneOf<MyType, 'val2' | 'val3'>(variable, 'val2', 'val3')) {
    // typeof variable == 'val2' | 'val3'
}

是否可以创建函数 hasOneOf 来推断泛型类型并返回由参数定义的联合 ('val2', 'val3' => 'val2' | 'val3') ?

【问题讨论】:

  • 您是在寻找一种允许可变数量参数的解决方案,还是像您的示例中那样将其固定为 2?
  • 您可以在提供参数时使用const assertion:hasOneOf(variable, 'val2' as const, 'val3' as const),以防止'val2'和'val3'类型扩大到'val1' | 'val2' | 'val3'
  • 你在寻找类似tsplay.dev/w8KVVW的东西吗?
  • @jsejcksn 我正在寻找可变数量的参数
  • @captain-yossarian 除了它对字符串联合来说不是类型安全的,它可以工作!我将它更新为类型安全:tsplay.dev/wOz26W 但是它只绑定到一个联合类型,我希望它对任何联合类型都是通用的

标签: typescript types typescript-generics


【解决方案1】:

如果您正在寻找一个接受可变数量的联合值的解决方案,以下是您问题中的一个变体。您可以将readonly 数组作为第二个参数传递,编译器将根据其成员的类型创建一个联合。 (我认为添加数组括号和as const 断言仍然比提供类型参数更简洁):

TS Playground link

function isInUnion <T, U extends T>(value: T, values: readonly U[]): value is U {
  return values.indexOf(value as U) >= 0;
}

let str = 'val1'; // string

if (isInUnion(str, ['val2', 'val3'] as const)) {
  str // "val2" | "val3"
}

let num = 1; // number

if (isInUnion(num, [2, 3] as const)) {
  num // 2 | 3
}

原答案:

您可以为此使用type predicate:

TS Playground link

function isInUnion <S1 extends string, S2 extends string>(
  value: string,
  str1: S1,
  str2: S2,
): value is S1 | S2 {
  return value === str1 || value === str2;
}

let str = 'val1'; // string

if (isInUnion(str, 'val2', 'val3')) {
  // in this block, str is "val2" | "val3"
}

【讨论】:

  • 这只适用于两个参数
  • @GuerricP 它也仅适用于扩展字符串的值,就像在问题中一样。该问题询问了两个参数。
  • @jsejcksn 考虑使用可变元组类型。一旦你将推断出整个数组,就不需要使用as const 断言
  • @Aik 请看这个tsplay.dev/WK7KMW
  • @captain-yossarian,是的,这是解决方案,谢谢!我只将参数从数组更新为 ...args 所以它不需要在数组中包装测试值
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-30
  • 2019-09-12
  • 2018-11-01
  • 2016-11-01
  • 2020-03-12
  • 1970-01-01
相关资源
最近更新 更多