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裏的依賴也要正確。

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