TypeScript按模块引入d3报错div.transition() is not a function的解决方案

一般来说,直接导入整个d3,我们会这么写:

import * as d3 from 'd3';

这样,我们就可以像在js里一样,使用熟悉的d3.select了。

但是因为不想一次性导入整个d3给项目增加大小,所以我就对d3进行了按模块导入:

import * as d3 from 'd3-selection';

这个其实也不影响select,但是因为我想给一个div增加transition的效果,就写了这么一段代码:

div.transition()
    .duration(500)
    .style('opacity', 0.9);

这个看起来是没啥问题的,但是使用的时候控制台就会报错div.transition() is not a function。上网查了一下,有很多人说升级d3的版本,但是我用的是最新的5.x,而且transition方法是在d3-selection这个模块里的:

declare module 'd3-selection' {
    interface Selection<GElement extends BaseType, Datum, PElement extends BaseType, PDatum> {
        transition(name?: string): Transition<GElement, Datum, PElement, PDatum>;
    }
}

找了很长时间,后来发现,事实上transition方法是通过d3-transition这个模块挂载到selection上的,并不属于d3-selection这个模块本身。我们可以看看d3的源码(省略了无关的部分):

// node_modules/d3-transition/src/selection/index.js
import {selection} from "d3-selection";
import selection_transition from "./transition.js";

selection.prototype.transition = selection_transition;

所以,如果直接导入d3-selection,是肯定找不到这个方法的。解决方案很简单,就是添加一个依赖,导入这个包:

import * as d3 from 'd3-selection';
import 'd3-transition';

但是,为什么会有这种误导呢,是d3写错了吗?再仔细看看package.json:

"devDependencies": {
    "@types/d3": "^5.7.2"
}

原因就在这里了。因为导入的是整个d3的类型声明,他默认我已经导入了全部的依赖,所以才会把transition方法放到Selection接口里。如果我们看一下d3-selection模块的类型声明(node_modules/@types/d3-selection/index.d.ts),就会发现,里面并没有transition方法。

所以,不仅仅在导入依赖的时候要正确导入,而且在node_modules里的依赖也要正确。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章