如何使 data() 键函数与 TypeScript 一起使用?

Him*_*shu 5 d3.js typescript

我试图用一个自定义按键功能.data().selectAll()在D3的选择。但是,让它兼容 TypeScript 变得如此痛苦。

如果没有 key 函数,元素将不会被正确删除,因为默认情况下 D3 使用索引来检查更新。

所以,这是JavaScript代码片段,按预期工作正常:

const circles = svg
        .select("g")
        .selectAll("circle")
        .data(data, d => d.val);
Run Code Online (Sandbox Code Playgroud)

TypeScript尝试同样的方法,

interface IData {
  val: number;
}
Run Code Online (Sandbox Code Playgroud)

尝试 1

const circles = svg
        .select("g")
        .selectAll("circle")
        .data<IData>(data, (d) => d.val);
Run Code Online (Sandbox Code Playgroud)
Object d is of type 'unknown'.  TS2571

    35 |         .select("g")
    36 |         .selectAll("circle")
  > 37 |         .data<IData>(data, (d) => d.val);

Run Code Online (Sandbox Code Playgroud)

尝试 2

Object d is of type 'unknown'.  TS2571

    35 |         .select("g")
    36 |         .selectAll("circle")
  > 37 |         .data<IData>(data, (d) => d.val);

Run Code Online (Sandbox Code Playgroud)
No overload matches this call.
  Overload 1 of 3, '(data: IData[], key?: ValueFn<SVGSVGElement | Element | EnterElement | Document | Window | null, IData, string> | undefined): Selection<...>', gave the following error.
    Argument of type '(this: SVGSVGElement | Element | EnterElement | Document | Window | null, d: IData) => number' is not assignable to parameter of type 'ValueFn<SVGSVGElement | Element | EnterElement | Document | Window | null, IData, string>'.
      Type 'number' is not assignable to type 'string'.
  Overload 2 of 3, '(data: ValueFn<BaseType, unknown, IData[]>, key?: ValueFn<SVGSVGElement | Element | EnterElement | Document | Window | null, IData, string> | undefined): Selection<...>', gave the following error.
    Argument of type 'IData[]' is not assignable to parameter of type 'ValueFn<BaseType, unknown, IData[]>'.
      Type 'IData[]' provides no match for the signature '(this: BaseType, datum: unknown, index: number, groups: BaseType[] | ArrayLike<BaseType>): IData[]'.  TS2769
Run Code Online (Sandbox Code Playgroud)

而且,如果没有数据的关键功能,一切都可以正常工作:

const circles = svg
        .select("g")
        .selectAll<SVGSVGElement, IData>("circle")
        .data<IData>(data, (d) => d.val);
Run Code Online (Sandbox Code Playgroud)

alt*_*lus 5

文档中可以看出,关键函数需要返回一个字符串(重点是我的):

通过计算每个数据和元素的字符串标识符,可以指定一个函数来控制将哪个数据分配给哪个元素,替换默认的按索引连接。

这也可以通过查看看出类型定义selection.data()

data<NewDatum>(data: NewDatum[], key?: ValueFn<GElement | PElement, Datum | NewDatum, string>): Selection<GElement, NewDatum, PElement, PDatum>;
Run Code Online (Sandbox Code Playgroud)

这里的关键函数定义为

key?: ValueFn<GElement | PElement, Datum | NewDatum, string>
Run Code Online (Sandbox Code Playgroud)

ValueFn类型为

export type ValueFn<T extends BaseType, Datum, Result> = (this: T, datum: Datum, index: number, groups: T[] | ArrayLike<T>) => Result;
Run Code Online (Sandbox Code Playgroud)

看上面两个定义不难看出,Resultkey函数定义的type参数设置为string,这就是你编译出错的原因。

从您的键函数返回一个字符串将解决这个问题:

.data(data, d => "" + d.val);
Run Code Online (Sandbox Code Playgroud)

  • 我尝试将结果转换为字符串,但现在“d.val”中的“d”出现错误,提示“对象的类型未知”。这很奇怪,因为打字稿知道我的数据是什么,当我将鼠标悬停在数据上时,它会显示 `const data: PieArcDatum&lt;PieSliceType&gt;[]`。那么为什么“d”类型未知呢? (3认同)