typescript - 如何在打字稿中使用带有元组的array.map?
问题描述
每当我array.map
在元组上使用时,Typescript 都会将其推断为通用数组。例如,这里有一些简单的 3x3 数独游戏:
const _ = ' ' // a "Blank"
type Blank = typeof _
type Cell = number | Blank
type Three = [Cell, Cell, Cell]
type Board = [Three, Three, Three]
const initialBoard: Board = [
[_, 1, 3],
[3, _, 1],
[1, _, _],
]
// Adds a `2` to the first cell on the first row
function applyMove(board: Board): Board {
// errors here
const newBoard: Board = board.map((row: Three, index: number) => {
if (index === 0) return <Three> [2, 1, 3]
return <Three> row
})
return newBoard
}
function applyMoveToRow(row: Three): Three {
// return [2, 1, 3] // This works
const newRow: Three = [
2,
...row.slice(1, 3)
]
return newRow
}
TS错误是:
Type '[Cell, Cell, Cell][]' is missing the following properties from type
'[[Cell, Cell, Cell], [Cell, Cell, Cell], [Cell, Cell, Cell]]': 0, 1, 2 .
它在一个 TS Playground 中。
有没有办法告诉打字稿,当我映射一个元组时,它会返回一个相同类型的元组,而不仅仅是一个数组?我尝试过非常明确,注释我所有的返回值等,但这并没有起到作用。
Typescript github上有一个关于这个的讨论:https ://github.com/Microsoft/TypeScript/issues/11312
但我一直无法从中得到解决方案。
解决方案
TypeScript 在调用时不会尝试保留元组长度map()
。此功能在microsoft/TypeScript#11312中请求,在microsoft/TypeScript#11252中实现,并在microsoft/TypeScript#16223中恢复,因为它与现实世界的代码有关。有关详细信息,请参阅microsoft/TypeScript#29841。
但是,如果您愿意,您可以合并您自己的签名声明Array.prototype.map()
,以说明它保留了元组的长度。这是一种方法:
interface Array<T> {
map<U>(
callbackfn: (value: T, index: number, array: T[]) => U,
thisArg?: any
): { [K in keyof this]: U };
}
那么你的代码可以写成如下:
function applyMove(board: Board): Board {
return board.map(
(row: Three, index: number) => (index === 0 ? applyMoveToRow(row) : row)
);
}
function applyMoveToRow(row: Three): Three {
return [2, row[1], row[2]];
}
并且不会有错误。请注意,我没有费心尝试处理Array.prototype.slice()
. 尝试表示对元组类型的作用将是大量的努力slice()
,特别是因为没有真正支持元组长度操作......这意味着您可能需要一堆重载签名或其他类型的技巧来完成它。如果您只打算使用slice()
短数组,您不妨像我上面所做[2, row[1], row[2]]
的那样使用编译器确实理解的索引访问。
或者,如果您打算将它用于更长的数组,但在代码中使用次数很少,您可能只想使用类型断言来告诉编译器您知道自己在做什么。就此而言,如果您只做map()
少量次,您也可以在此处使用类型断言,而不是上面重新声明map()
' 的签名:
function applyMove(board: Board): Board {
return board.map(
(row: Three, index: number) => (index === 0 ? applyMoveToRow(row) : row)
) as Board; // assert here instead of redeclaring `map()` method signature
}
无论哪种方式都有效...类型断言的类型安全性较低但更直接,而声明合并更安全但更复杂。
希望有帮助;祝你好运!
推荐阅读
- python - 基于多列的 Python 合并
- javascript - Javascript 在 catch 块中丢失了回溯
- widget - Databricks:在查询中调用小部件值
- visual-studio - 限制多值参数选择 SSRS 的数量
- airflow - 如果工作人员本身出现故障,在 Celery 工作人员上运行的气流传感器会发生什么情况
- three.js - AR.js aframe 对象显示也没有指向标记
- php - 如何使用 PHPmailer 发送参数以在 cid 内部进行跟踪
- sql - Rewrite Join 引入了没有 DISTINCT 的重复行
- angular - 如何从 Jasmine 测试中执行 switchMap 和点击 rxJS 函数?
- python - 我可以自定义自己的画笔风格吗?