【问题标题】:Compilation errors when drawing a piechart using D3.js, TypeScript and Angular使用 D3.js、TypeScript 和 Angular 绘制饼图时出现编译错误
【发布时间】:2025-12-30 05:50:12
【问题描述】:

我正在尝试显示一个饼图并且它确实在工作,即使我收到 TypeScript 编译错误:Argument of type '(d: any) => {}' is not assignable to parameter of type 'datum: Arc<number>, index: number, outerIndex: number) => number | string | boolean'. Type '{}' is not assignable to type 'number | string | boolean'. Type '{}' is not assignable to type 'boolean'.

过去 2 年我一直在使用 TypeScript,但上面的那行让我头晕目眩。我不知道发生了什么,我尝试了一些东西,但到目前为止没有任何效果。

这是实际绘制饼图的代码:

function drawChart(){
            var width = 960,
                height = 500,
                radius = Math.min(width, height) / 2;

            var colourValues = d3.scale.ordinal().range(d3.values(that.ColoursService.colours));

            var arc = d3.svg.arc()
                .outerRadius(radius - 10)
                .innerRadius(radius - 70);

            var pie = d3.layout.pie()
                .sort(null)
                .value(function(d: any) {return d.quantity});

            var svg = d3.select('.pie-chart').append('svg')
                .attr('width', width)
                .attr('height', height)
                .append('g')
                .attr('transform', 'translate(' + width / 2 + ',' + height/2 + ')');

            var g = svg.selectAll('.arc')
                .data(pie(data))
                .enter().append('g')
                .attr('class', 'arc');

            g.append('path')
                .attr('d', <any>arc)
                .attr('fill', function(d: any) {
                    return colourValues(d.data.category); 
                });
        }

这是打字稿突出显示错误的地方,波浪线出现在“功能”字下方。我需要让 TypeScript 编译器通过,但我不知道怎么做。

【问题讨论】:

    标签: javascript angularjs d3.js typescript


    【解决方案1】:

    虽然使用&lt;any&gt; 会消除编译器的抱怨,但您基本上是在回避强类型检查,这可以说是首先使用 Typescript 的要点之一。我在这个问题上苦苦挣扎了很长时间,最后,通过反复试验以及与the d3.d.ts definition for d3.svg.arc 的大量优质时间,我能够想出一种方法来使所有类型对齐。这是一个演示如何在不使用&lt;any&gt; 的情况下获取饼图的解决方案。关键是你需要指定一个interface 来描述你的输入的形状,即你的数据:

    interface Datum {
        category: string;
        quantity: number;
    }
    
    function drawChart(data: Array<Datum>) {
    
        let width = 960,
            height = 500,
            radius = Math.min(width, height) / 2,
            colourValues = d3.scale.category10();
    
        // specify Datum as shape of data
        let arc = d3.svg.arc<d3.layout.pie.Arc<Datum>>()
            .innerRadius(radius - 70)
            .outerRadius(radius - 10);
    
        // notice accessor receives d of type Datum
        let pie = d3.layout.pie<Datum>().sort(null).value((d: Datum):number => d.quantity);
    
        // note input to all .attr() and .text() functions
        // will be of type d3.layout.pie.Arc<Datum>
        let fill = (d: d3.layout.pie.Arc<Datum>): string => colourValues(d.data.category);
        let tfx  = (d: d3.layout.pie.Arc<Datum>): string => `translate(${arc.centroid(d)})`;
        let text = (d: d3.layout.pie.Arc<Datum>): string => d.data.category;
    
        let svg = d3.select('.pie-chart').append('svg')
            .attr('width', width)
            .attr('height', height)
            .append('g')
            .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
    
        // create a group for the pie chart
        let g = svg.selectAll('.arc')
            .data(pie(data))
            .enter().append('g').attr('class', 'arc');
    
        // add pie sections
        g.append('path').attr('d', arc).attr('fill', fill);
    
        // add labels
        g.append('text').attr('transform', tfx).text(text);
    }
    

    请注意,我将您的 ColourService 替换为标准的 d3 颜色类别函数之一,但只要 colourValues() 返回一个指定填充颜色的字符串,它就应该仍然有效。

    希望这个示例展示了如何让您的自定义数据类型与 d3 和 Typescript 一起使用。

    【讨论】:

    • 感谢您为我澄清这一点。我不喜欢使用 ,它违背了使用 TypeScript 的目的。
    【解决方案2】:

    好吧,我知道发生了什么,虽然我不完全理解 D3 如何与 TypeScript 一起工作。基本上有两种解决方案:

    第一个,我在数据参数和返回值(字符串、数字或布尔值)上设置特定接口,然后将返回值类型转换为字符串 - 这太罗嗦了。

    g.append('path')
        .attr('d', <any>arc)
        .attr('fill', function (datum: d3.layout.pie.Arc<any>): number | string | boolean {
            return <string>colourValues(datum.data.category); 
      });
    

    第二种解决方案对眼睛来说更容易。我只添加了:any 作为函数的返回类型。

    g.append('path')
        .attr('d', <any>arc)
        .attr('fill', function (d: any): any {
            return colourValues(d.data.category); 
        });
    

    我仍然不完全了解如何连接我在 D3 中与之交互的数据模型 - 每次我尝试使用已经通过 angular.IPromise&lt;interfaceNameOfTheReturnData&gt; 在包装在 angular 指令链接中的 D3 函数中成功实现的承诺解析中实现的接口函数,我遇到 TypeScript 编译错误,必须使用 any 类型。

    【讨论】: