typescript - 如何在 Typescript 中使用可变元组类型?
问题描述
我正在努力理解如何在 Typescript中使用可变元组类型。我试图通读文档,以及 GitHub 上的一些问题,但示例总是比“超级基本”有点奇怪,所以我想知道是否有人可以帮我输入几个“超级基本”,这样我就可以也许用那些来“得到它”。
假设我们有这些功能:
function wrap(...items) {
return items.map(item => ({ value: item }))
}
function wrapArray(items) {
return items.map(item => ({ value: item }))
}
function unwrap(...items) {
return items.map(item => item.value)
}
function unwrapArray(items) {
return items.map(item => item.value)
}
我如何输入这些,以便例如以下内容可以按类型工作?
const items = [{ value: 4 }, { value: 'foo' }]
const [num, str] = unwrap(...items)
console.log(num.toFixed(2))
console.log(str.charAt(0))
这是一个带有功能的游乐场,以及每个功能的“测试”。他们使用的是非可变类型,这当然不太有效,而且我不明白如何编写它们以便它们起作用:
TypeScript Playground
解决方案
以下是我倾向于输入它们的方式:
type Wrapped<T extends any[]> = { [I in keyof T]: { value: T[I] } };
function wrap<T extends any[]>(...items: T) {
return items.map(item => ({ value: item })) as Wrapped<T>;
}
function unwrap<T extends any[]>(...items: Wrapped<T>) {
return items.map(item => item.value) as T;
}
function wrapArray<T extends any[]>(items: readonly [...T]) {
return items.map(item => ({ value: item })) as Wrapped<T>
}
function unwrapArray<T extends any[]>(items: readonly [...Wrapped<T>]) {
return items.map(item => item.value) as T;
}
评论:
这些函数都是通用的,非包装元素
T
的元组。因此wrap()
,wrapArray()
取一个类型的值T
作为输入,而unwrap()
返回unwrapArray()
一个类型的值T
作为输出。Wrapped<T>
是一个映射元组,它包装了 的每个元素T
。wrap()
并wrapArray()
返回一个类型的值Wrapped<T>
作为输出,而unwrap()
将unwrapArray()
一个类型的值Wrapped<T>
作为输入。编译器无法自行验证或理解
items.map(...)
将 aT
变为 aWrapped<T>
或反之亦然。有关原因的详细信息,请参阅此问题/答案。我们没有试图让编译器这样做,而是简单地断言的返回值map()
是我们想要的类型(即,as T
或as Wrapped<T>
)。在
wrap()
任何unwrap()
地方都没有使用可变参数元组类型。这种元组类型可以通过在元组中使用数组或元组类型的剩余参数来识别,例如[1, ...[2, 3, 4], 5]
.wrapArray()
andunwrapArray()
函数使用可变元组类型作为输入(而readonly [...T]
不仅仅是T
),但这只是为了在使用元组时帮助推断元组,并不是必需的。因此,当您询问可变元组类型时,该示例不需要使用它们。
让我们试一试:
const items = [{ value: 4 }, { value: 'foo' }] as const; // <-- note well
const [num, str] = unwrap(...items);
// or const [num, str] = unwrapArray(items);
console.log(num.toLocaleString());
console.log(str.charAt(0));
这现在有效,但请注意,我必须使用一个const
断言来允许编译器推断这items
是一个正好包含两个元素的元组,第一个是 a {value: 4}
,第二个是 a {value: "foo"}
。没有这个,编译器使用它的标准启发式假设一个数组是可变的并且它的长度和它的元素的身份可以改变......这意味着它items
就像Array<{value: string} | {value: number}>
并且没有希望将它解包成一个元组。
推荐阅读
- regex - 在编写正则表达式以捕获 DNS 日志时需要帮助
- sql - MS SQL 创建带有转置输出的 SP
- queue - 以用户为中心的工作流程的气流 DAG 设计
- google-admin-sdk - 用于邮件日志查询的 Google Admin SDK API
- json - 对于我想要实现的目标,这是正确的 json 格式吗?
- java - @bean 和 @Autowired 实际上是如何工作的?
- haskell - 有没有办法指向尚未在最后一个haskell LTS 上的servant-server 0.15?
- javascript - 在特定项目上创建警告消息
- azure - 将 Azure 应用程序代理与应用服务一起使用
- c - 避免在 linux ( GCC ) "No-echo" 上使用 getch() 按 enter