【问题标题】:Mapping ...args to tuple of child type将 ...args 映射到子类型的元组
【发布时间】:2020-01-17 14:15:31
【问题描述】:

我有一个场景,我想要一个可以接受任意数量的通用对象参数的函数。

我希望结果返回一个元组,其中该对象的每个通用参数都是元组位置类型。

示例

type Wrap<T> = {
    obj: T;
}

function UnWrap<T extends Array<Wrap<One|Two>>>(...args:T){ //return type?
    return args.map(i => i.obj);
}

type One = {
    foo: string;
}

type Two = {
    bar: string;
}

let one: Wrap<One> = {obj: {foo: 'abc'}}

let two: Wrap<Two> ={obj: {bar: 'abc'}}

// res type should be [One, Two, Two, One]
let res = UnWrap(one, two, two, one) 

如果我只返回传入的确切类型,我可以让该类型工作:

function ReturnSelf<T extends Array<Wrap<One|Two>>>(...args:T): typeof args{
    return args;
}

但我不确定如何索引['obj'] 类型。我想也许可以使用映射类型来做到这一点,但我不太明白。

Typescript Playground link

【问题讨论】:

  • 我对问题陈述有点困惑。在运行时没有类型或接口,所以 afaik 类型需要是泛型类型的一部分(可能是接口契约的一部分)。然后你可以简单地在一个元组中或多或少地映射出你已经在做的输出。
  • @cYrixmorten 不确定我理解你的意思......我正在尝试创建与重新选择“createSelector”的工作方式类似的东西(不在域中)。 github.com/reduxjs/reselect
  • 没关系,看来我根本没有抓住你试图完成的任务的本质。

标签: typescript mapped-types


【解决方案1】:

是的,自从 TypeScript 3.1 引入 the ability to map tuple/array types 以来,您就可以使用映射类型来执行此操作。您可以像以前那样以“前进”方式进行操作:

function UnWrap<T extends Array<Wrap<One | Two | Three>>>(...args: T) {
  return args.map(i => i.obj) as {
    [K in keyof T]: T[K] extends Wrap<infer U> ? U : never
  };
}

let res2 = UnWrap(one, two, three, two); // [One, Two, Three, Two]

或“反向”方式,使用inference from mapped types:

function UnWrap2<T extends Array<One | Two | Three>>(
  ...args: { [K in keyof T]: Wrap<T[K]> }
) {
  return args.map(i => i.obj) as T;
}
let res3 = UnWrap2(one, two, three, two); // [One, Two, Three, Two]

如您所见,无论哪种方式都可以工作...无论哪种方式,编译器都无法理解 args.map(i =&gt; i.obj) 执行您正在执行的类型操作,因此您需要使用 @ 987654323@ 或等效的一个(例如使用单个overload 签名)。

好的,希望对您有所帮助。祝你好运!

Link to code

【讨论】:

  • 漂亮。我意识到我的例子有点偏离,因为“obj”的类型实际上并不提前知道。但是,我能够用Wrap&lt;any&gt; 替换Wrap&lt;One|Two&gt;,令我惊讶的是,它仍然有效!打字稿很棒
猜你喜欢
  • 2020-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 2017-09-25
相关资源
最近更新 更多