【问题标题】:Is there any way to get a names of arguments of function in typescript? [duplicate]有没有办法在打字稿中获取函数参数的名称? [复制]
【发布时间】:2021-05-11 17:11:49
【问题描述】:

我正在尝试制作一个包装函数,它将一个函数作为输入并返回一个新类型的函数,该函数允许参数列表和包含参数名称作为键的对象。

我为此编写了以下代码。该代码按预期工作。问题是我传递了一个附加类型,其中包含作为参数名称的键和作为该参数类型的值。我想动态地做到这一点。我想访问参数的名称

//I want remove this Args parameters and make it dynamically using F type.
function wrapper<F extends (...args: any) => any, Args>(func: unknown) {
   type ParametersList = Parameters<F>;
   return func as (...args: [Args] | ParametersList) => ReturnType<F>;
}
const add = (x: number, y: number) => x + y;
const wrappedAdd = wrapper<typeof add, { x: number; y: number }>(add);

Parameters 函数返回一个命名元组(我猜这是一个新特性)。有什么方法可以获取该元组的名称/标签。您也可以建议任何其他方式。 谢谢。

###编辑: 好的,经过一些研究,我发现我们无法获取函数参数的名称。所以现在我的目标是稍微缩短我的代码。在上面的代码中,我传递了一个对象来代替Args。我只想传递一个字符串数组。

const wrappedAdd = wrapper<typeof add, ["x", "y"]>(add);

我想使用这个数组动态生成一个对象。谢谢

【问题讨论】:

  • 并非所有参数都可能有名称。如果funcwrapper 一样有一个rest 参数怎么办?作为其余参数传递的参数的名称应该是什么?通常如果你需要命名参数,你应该传递一个对象而不是位置参数。
  • @cdhowie 我们可以认为该函数将始终具有命名参数,而不是像add函数这样的静止参数
  • @cdhowie 我想你没有得到我的问题。考虑是否存在具有所有命名参数的函数。有什么方法可以将这些名称作为 typescript 元组或数组类型获取?
  • @cdhowie 不,这不能回答我的问题。我想在运行时命名不在变量中的打字稿类型。
  • @captain-yossarian 哦。 NP。我会采用其他方法。感谢您的宝贵时间

标签: javascript typescript


【解决方案1】:

我认为最好在全局范围内定义任何类型。



type Elem = any;

type Predicate<Key extends number, Value extends Elem> = Record<Key, Value>

type Reduce<
    Arr extends ReadonlyArray<Elem>,
    Result extends Record<string, any> = {}
    > = Arr extends []
    ? Result
    : Arr extends [infer H]
    ? Result & Predicate<0, H>
    : Arr extends readonly [...infer Tail, infer H]
    ? Tail extends ReadonlyArray<Elem>
    ? Reduce<Tail, Result & Predicate<Tail['length'], H>>
    : never
    : never;


function wrapper<F extends (...args: any) => any>(func: F):
    (...args: [Reduce<Parameters<F>>] | Parameters<F>) => ReturnType<F> {
    return func
}

const add = (x: number, y: string, z: number[]) => x + y;

const wrappedAdd = wrapper(add);
const add = (x: number, y: string, z: number[]) => x + y;

const wrappedAdd = wrapper(add)({ 0: 1, 1: 'hello', 2: [1] }); // ok
const wrappedAdd2 = wrapper(add)(1, 'hello', [1]); // ok


顺便说一句,这里不需要使用类型断言。我的意思是你可以摆脱as运营商

如果您对此类类型的更多示例感兴趣,可以查看我的article

这里你有 Reduce 类型在几乎纯 JS 中的表示:

const reduce = <T,>(arr: T[], cache = {}) => {
    if (arr.length === 0) {
        return cache
    }
    if (arr.length === 1) {
        const [head] = arr;
        return { ...cache, [0]: head }
    }
    const [head, ...rest] = arr;
    return reduce(rest, { ...cache, [rest.length]: head })
}

Playground

就像@jcalz 说的:

参数名称在类型系统中是不可观察的,除非是 IntelliSense 的文档

TS中没有办法推断出参数名并放入其他类型,所以我决定使用索引类型。

0 用于第一个参数,1 用于第二个参数,等等......

关于使用参数名称:

Docs

但有一个地方开始出现差异:可读性。

它们纯粹是为了文档和工具。

const add = (x: number) => x + x

type Args = Parameters<typeof add>

type Infer = Args extends [infer R] ? R : never // number
type Infer2 = Args extends [x: infer R] ? R : never // number

因此,我认为在当前版本的 TypeScript 中是不可能的。

【讨论】:

  • 非常感谢您的回答。使用数字作为对象的键会破坏目的。随着参数数量的增加,它会遇到与单独传递参数相同的问题
  • @MaheerAli 我更新了
  • 有什么方法可以让我们自己传递一个类型作为字符串数组,其中包含键名。然后我们可以使用这些键从参数元组中生成对象那些键和对应的值?
  • @MaheerAli 您能否提供一个具有预期结果的示例?确保我们在同一条船上:)
  • 好的兄弟我更新了问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-27
  • 2020-05-12
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
  • 2020-09-21
  • 1970-01-01
相关资源
最近更新 更多