D3 .extent() 拒绝打字稿中的日期数组

D3 .extent() rejecting array of Dates in typescript

提问人:Luke 提问时间:7/12/2023 最后编辑:Luke 更新时间:7/18/2023 访问量:126

问:

我正在努力在打字稿中使用 d3 的 .extent() 函数。

我这里有一些代码,可以创建日期之外的 Date 对象

 const dates:(Date | null)[] = data.map(row => d3.timeParse("%Y-%m-%d")(row.Date))

当我控制台记录日期变量时,它看起来像这样

[Sat Jun 24 2023 00:00:00 GMT-0700 (Pacific Daylight Time), Sat Jun 24 2023 00:00:00 GMT-0700 (Pacific Daylight Time), Fri Jun 23 2023 00:00:00 GMT-0700 (Pacific Daylight Time), Fri Jun 23 2023 00:00:00 GMT-0700 (Pacific Daylight Time), Fri Jun 23 2023 00:00:00 GMT-0700 (Pacific Daylight Time), ...]

因此,我知道我的日期变量充满了 Date 对象,就像预期的那样......

但是,当我尝试使用 d3.extent() 函数查找最高和最低日期时

const xScale = d3
      .scaleTime()
      .domain(d3.extent(dates))
Argument of type '[undefined, undefined] | [string, string]' is not assignable to parameter of type 'Iterable<Date | NumberValue>'.

不过,我对为什么会这样感到困惑,因为我的日期变量实际上完全是日期,而不是错误中表达的“[未定义,未定义] |[字符串,字符串]'。

我经过的东西有什么问题?我应该如何将日期传递给打字稿中的 extent() 函数?

JavaScript 打字稿 日期 D3.js 可视化

评论


答:

1赞 VonC 7/14/2023 #1

筛选实例是一种很好的方法,但您可以得到:
.
nullType '(Date | null)[]' is not assignable to type 'Date[]'. Type 'Date | null' is not assignable to type 'Date'. Type 'null' is not assignable to type 'Date'

这是因为即使在筛选操作之后,TypeScript 仍在考虑数组中值的可能性。null

应在 filter 函数中包含类型谓词。这明确告诉 TypeScript 筛选器的结果将仅包含对象,而不包含值。date is DateDatenull

const dates:(Date)[] = data
    .map(row => d3.timeParse("%Y-%m-%d")(row.Date))
    .filter((date): date is Date => date !== null);

这确实创建了一个过滤器函数,该函数不仅检查日期是否不是,而且还使用类型保护来告诉 TypeScript 通过此过滤器的每个项目都是 .
(另请参阅 Shreejit Rajbanshi 的“类型谓词:在 Typescript 中过滤数组
nullDate)

OP 使用:

dates: (Date)[]:在筛选操作 () 之后,确保过滤掉所有值。因此,您只剩下一个对象数组。因此,您需要键入 as 而不是 。filter((date): date is Date => date !== null)nullDatedatesDate[](Date | null)[]

紧随其后的是:

const xScale = d3
    .scaleTime()
    .domain(d3.extent(dates) as unknown as [Date, Date]);

我提议的原始代码用于告诉 TypeScript 信任我们,域将是两个对象的元组。as [Date, Date]Date

这是一个类型断言,它不会改变代码的实际值或操作,而只是通知 TypeScript 类型。这不会保护您在运行时免受未定义值的影响,它纯粹用于 TypeScript 的静态类型检查。因此,为什么我们在过滤器操作期间之前进行了检查。as [Date, Date]nullnull

但 OP 使用了:

dates as unknown as Date[]:当 TypeScript 不能直接从一个类型断言到另一个类型时,使用此构造,但我们作为开发人员知道这是可能的。通过强制转换为 first,您基本上绕过了 TypeScript 的类型检查,然后将其重新断言为 .unknownDate[]

评论

0赞 Luke 7/17/2023
解决方案大部分奏效!需要将 d3.extent(dates) 更改为 [Date, Date]) 作为未知的日期,并且需要将 dates:(Date | null)[] 更改为 dates:(Date)[],但之后工作
0赞 VonC 7/17/2023
@Luke OK。我已经相应地编辑了答案中的代码。如果我误解了您的评论,请告诉我。
0赞 Luke 7/17/2023
谢谢!是的,在域行上对我有用的是 .domain(d3.extent(dates) as unknown as [Date, Date]) 。所以如果你愿意,你可以把它编辑到你的答案中。但是,是的,经过一些小的更改后,您的解决方案效果很好!非常感谢
0赞 VonC 7/18/2023
@Luke 感谢您的反馈。我已经相应地编辑了答案。