从同级属性推断/缩小函数参数范围 [英] Infer/narrow function argument from sibling property

查看:0
本文介绍了从同级属性推断/缩小函数参数范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想根据同级属性缩小函数参数的类型。我知道存在类型会有帮助,但它们不可用,所以我使用了一个助手函数。多亏了评论中的jcalz,我现在有了这个

// helper function
function helper<T extends readonly unknown[]>(o: {
  choices: T;
  func: (opts: T[number]) => T[number];
}) {
  return o;
}

helper({
  choices: [
    "one",
    "two",
    "three",
  ], // as const
  func(o) { // should be "one" | "two" | "three", but is string
    return o;
  }
})
我希望func中的o"one" | "two" | "three"类型,所以我的问题是,类型脚本不会将选项推断为元组,而是string[]。我无法将as const添加到choices,因为该函数将在Java脚本中调用。

我知道我可以将选项和函数拆分到helper函数的单独参数中,但这是不可能的,因为对象中将有更多属性。属性的目的是描述func、它需要什么作为输入以及它返回什么。

最终目标是让helper函数用类型脚本编写,但在Java脚本中用作类型批注。因此,我不能在调用函数时提供任何类型,也不能在用注释标记的地方使用as const

推荐答案

您希望helper()将数组文字["one", "two", "three"]视为类型["one", "two", "three"];即,将其视为字符串literal typestuple,而不仅仅是string[]。从函数的调用方端可以很容易地做到这一点;调用方可以使用类似["one", "two", "three"] as constconst assertion。但是,如果调用方不想(或不能)使用const断言,让函数本身来做这件事就更好了。

我在一段时间前打开了microsoft/TypeScript#30680,请求一些简单的方法来完成此操作。也许它会看起来像:

// INVALID TYPESCRIPT SYNTAX, DO NOT TRY THIS
//                        vvvvv
function helper<T extends const readonly unknown[]>(o: {
    choices: T;
    func: (opts: T[number]) => T[number];
}) {
    return o;
}

其中const可以以某种方式应用于泛型类型参数。遗憾的是,这不是当前语言的一部分。

幸运的是,有一些技巧可以使编译器的行为有点类似。


如果您想给编译器一个提示,提示它应该推断文字类型,您可以查看microsoft/TypeScript#10676。如果类型参数constrained为包含string的类型,则编译器将倾向于推断字符串文字类型。number也是如此。因此,当不受约束的T(如T extends unknown)看到"one"时将推断string,而受约束的T extends string将推断"one"。如果您真的不想约束类型参数,那么您需要想出最宽的约束,显式地包含string和/或number。您不能使用the unknown type,因为T extends string | unknown立即折叠为T extends unknown。但是,您可以执行类似

的操作
type Narrowable = string | number | bigint | boolean | 
  symbol | object | undefined | void | null | {};

,然后写入T extends Narrowable,而不是T extends unknown。或者在您的情况下,T extends readonly Narrowable[]而不是T extends readonly unknown[]


如果希望编译器推断元组而不是数组类型,还有其他诀窍。TypeScrip 4.0引入variadic tuple types。如果U是类似数组的类型参数,则编译器将倾向于看到(arr: U)并推断U的无序数组类型。但如果您编写(arr: [...U])或`(arr:Readonly[...U]),它将倾向于推断元组类型。


将这些组合在一起:

function helper<T extends readonly Narrowable[]>(o: {
    choices: readonly [...T];
    func: (opts: T[number]) => T[number];
}) {
    return o;
}

并且您可以验证它是否正常工作:

helper({
    choices: [
        "one",
        "two",
        "three",
    ], // as const
    func(o) { // "one" | "two" | "three"
        return o;
    }
})

看起来不错。

Playground link to code

这篇关于从同级属性推断/缩小函数参数范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆