【问题标题】:TypeScript: Is it possible to map tuples in a typesafe way?TypeScript:是否可以以类型安全的方式映射元组?
【发布时间】:2021-12-15 05:05:55
【问题描述】:

如果我这样写:

declare function callbackFn<T>(entry: T): T extends string ? "string !" : "not string!";

const output= ([ "foo", 42 ] as const).map(callbackFn);

output 的类型是("string !" | "not string!")[] 有没有办法得到readonly [ "string !", "not string!" ]

谢谢

【问题讨论】:

标签: typescript


【解决方案1】:

可以在function-overloads的帮助下实现。

首先,让我们定义callbackFn

type CallbackFn<T> = T extends string ? "string !" : "not string!";

function callbackFn<T>(entry: T): CallbackFn<T>
function callbackFn<T>(entry: T) {
  return typeof entry === 'string' ? "string !" : "not string!"
}

我重载了callbackFn 并使用CallbackFn 类型实用程序来推断返回类型。

现在,我们需要用于映射的类型实用程序。考虑一下:

type MapUtility<T extends ReadonlyArray<unknown>> = {
  [Prop in keyof T]: CallbackFn<T[Prop]>
}

type Test1 = MapUtility<["foo", 42]> // ["string!", "not string!"]

既然所有的 utils 都设置好了,我们就可以编写我们的 main 函数了。请记住,没有必要使用as const 来推断文字参数。你可以使用variadic-tuple-types:

function map<
  Elem,
  Tuple extends Elem[]
>(tuple: [...Tuple]): MapUtility<Tuple>
function map(tuple: unknown[]) {
  return tuple.map(callbackFn)
}

// ["string !", "not string!"]
const output = map(["foo", 42])

整个例子:

type CallbackFn<T> = T extends string ? "string !" : "not string!";

function callbackFn<T>(entry: T): CallbackFn<T>
function callbackFn<T>(entry: T) {
  return typeof entry === 'string' ? "string !" : "not string!"
}


type MapUtility<T extends ReadonlyArray<unknown>> = {
  [Prop in keyof T]: CallbackFn<T[Prop]>
}

type Test1 = MapUtility<["foo", 42]> // ["string!", "not string!"]
  
function map<
  Elem,
  Tuple extends Elem[]
>(tuple: [...Tuple]): MapUtility<Tuple>
function map(tuple: unknown[]) {
  return tuple.map(callbackFn)
}

// ["string !", "not string!"]
const output = map(["foo", 42])

Playground

请记住,打字稿在map 之后不保留元组长度。见this答案。

This答案相关

附:如果您对 TypeScript 中的函数参数推断感兴趣,可以查看我的 article

【讨论】:

  • 非常感谢您的详细回答!为什么Json 在这里是相关的,为什么我们可以从Elem extends Json 中删除extends Json
  • @JosephGarrone 你是对的,我已经删除了它。不相关
  • 也非常感谢您使用函数重载来实现具有复杂返回类型的泛型函数的想法。我厌倦了不得不像任何东西一样投射。
  • @JosephGarrone,没问题。请记住,函数重载不会为您提供 100% 的安全性。它们是双变量的,但同时我相信这是在打字稿中最干净的方法
  • 是的,当然是的,但它不提供任何安全优势,但这样更清洁!
【解决方案2】:

如果您使用元组类型,我相信您必须避免使用 .map,请尝试以下方法:

    const mapTuple = (tuple: [unknown, unknown]) =&gt; [callbackFn(tuple[0], callbackFn(tuple[1])] as const;

这样你仍然保持元组类型作为返回类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-27
    • 2016-09-03
    • 2020-12-18
    • 2023-04-10
    • 2021-06-01
    • 2020-09-16
    • 2021-07-10
    • 2011-10-11
    相关资源
    最近更新 更多