2017-05-25 5 views
0

私は強く型を入れてメンテナンスしやすいようにしようとしています。typescript - 型のモジュールパターンを表す

ただし、メニューの変数のために、私は次のエラーを取得する:

[ts] 
Type '(x: number, y: number) => void' is not assignable to type 'ContextMenu'. 
    Property 'items' is missing in type '(x: number, y: number) => void'. 



import * as d3 from "d3"; 
import "d3-selection-multi"; 

interface ContextMenu { 
    (x: number, y: number) : void; 
    items(items?: string[]): string[] | this; 
    remove(): void; 
} 

export function contextMenu(): ContextMenu { 
    var height, 
     width, 
     margin = 0.1, // fraction of width 
     items = [], 
     rescale: boolean = false, 
     style = { 
      'rect': { 
       'mouseout': { 
        "fill": 'rgb(244,244,244)', 
        "stroke": 'white', 
        "strokeWidth": '1px' 
       }, 
       'mouseover': { 
        "fill": 'rgb(200,200,200)' 
       } 
      }, 
      'text': { 
       'fill': 'steelblue', 
       'font-size': '13' 
      } 
     }; 

    var menu: ContextMenu = function (x:number, y:number) { 
     menu.remove(); 
     scaleItems(); 

     // Draw the menu 
     d3.selectAll('svg.chart') 
      .append('g').attr('class', 'context-menu') 
      .selectAll('tmp') 
      .data(items).enter() 
      .append('g').attr('class', 'menu-entry') 
      .style('cursor', 'pointer') 
      .on('mouseover', function() { 
       d3.select(this).select('rect').styles((<any>style).rect.mouseover) }) 
      .on('mouseout', function() { 
       d3.select(this).select('rect').styles((<any>style).rect.mouseout) }); 

     d3.selectAll('.menu-entry') 
      .append('rect') 
      .attr('x', x) 
      .attr('y', (d, i) => y + (i * height)) 
      .attr('width', width) 
      .attr('height', height) 
      .styles((<any>style).rect.mouseout); 

     d3.selectAll('.menu-entry') 
      .append('text') 
      .text((d: string) => d) 
      .attr('x', x) 
      .attr('y', (d, i) => y + (i * height)) 
      .attr('dy', height - margin/2) 
      .attr('dx', margin) 
      .styles((<any>style).text); 

     // Other interactions 
     d3.select('body') 
      .on('click', function() { 
       d3.select('.context-menu').remove(); 
      }); 
    } 

    menu.remove = function() { 
     d3.selectAll(".context-menu").remove(); 
    }; 

    menu.items = function(_?) { 
     return (!arguments.length) 
     ? items 
     :(items = _, rescale = true, menu); 
    } 

    // Automatically set width, height, and margin; 
    function scaleItems() { 
     if (!rescale) { 
      return; 
     } 
     d3.selectAll('svg').selectAll('tmp') 
      .data(items).enter() 
      .append('text') 
      .text(d => d) 
      .styles(<any>style.text) 
      .attr('x', -1000) 
      .attr('y', -1000) 
      .attr('class', 'tmp'); 

     var z = d3.selectAll('.tmp') 
      .nodes() 
      .map((x:any) => x.getBBox()); 

     width = d3.max(z.map(x => x.width)); 
     margin = margin * width; 
     width = width + 2 * margin; 
     height = d3.max(z.map(x => x.height + margin/2)); 

     // cleanup 
     d3.selectAll('.tmp').remove(); 
     rescale = false; 
    } 
    return menu; 
} 

はハウ私は、コードのコンパイルを行うが、同じコードスタイル慣用的D3を保つことができますか?

答えて

1

悲しいことに、あなたのケースで機能を拡張するための慣用方法はありません。唯一の欠点は、メニュー機能をanyにキャストすることです。

var menu: ContextMenu = function (x:number, y:number) { 
    // .... 
} as any 

活字体は、関数リテラルを拡張対応するために、別の機能を呼び出し、「マージ名前空間」を持っています。

function menu() {} 
namespace menu { 
    export function remove() {} 
} 
menu.remove() // compiles 

ただし、namespaceは、モジュールのトップレベルにのみ表示されるか、別の名前空間にネストされます。関数クロージャで宣言することはできません。したがって、この場合はいずれにせよanyにフォールバックする必要があります。

関連する問題