Javascript 实施D3计划;“可重复使用图表”;打字脚本中的模式
下面第2节中的代码(工作示例)基于第1节中的代码,但改为使用箭头函数,并且基于中Mike Bostock的模式,即返回一个包含其他函数的函数 如果我尝试在typescript(演示)中运行第1节或第2节中的代码,它会说方法Javascript 实施D3计划;“可重复使用图表”;打字脚本中的模式,javascript,typescript,d3.js,Javascript,Typescript,D3.js,下面第2节中的代码(工作示例)基于第1节中的代码,但改为使用箭头函数,并且基于中Mike Bostock的模式,即返回一个包含其他函数的函数 如果我尝试在typescript(演示)中运行第1节或第2节中的代码,它会说方法addToChart和stop在类型(选择:any)=>()=>void上不存在 如何让typescript识别添加到返回函数中的函数属性(addToChart和stop)? 第1节 const mychart = function (){ let stop = false
addToChart
和stop
在类型(选择:any)=>()=>void
上不存在
如何让typescript识别添加到返回函数中的函数属性(addToChart
和stop
)?
第1节
const mychart = function (){
let stop = false;
const chart = function(selection){
function tick(){
console.log("tick");
}
return tick;
};
// Adding a function to the returned
// function as in Bostock's reusable chart pattern
chart.addToChart = function(value){
console.log("addToChart");
return chart;
};
chart.stop = function(){
return stop = true;
}
return chart;
}
const a = mychart();
const tick = a();
tick(); //logs tick
a.addToChart(); //logs "addToChart"
第2节
const mychart = () => {
let stop = false;
const chart = (selection) => {
function tick(){
console.log("tick");
}
return tick;
};
chart.addToChart = (value) => {
console.log("addToChart");
return chart;
};
chart.stop = () => {
return stop = true;
}
return chart;
}
const a = mychart();
const tick = a();
tick(); //logs tick
a.addToChart(); //logs "addToChart"
我想知道您是否可以使用接口/类:
interface IChart {
constructor: Function;
addToChart?: (number) => Chart;
stop: () => boolean;
}
class Chart implements IChart {
private _stop = false;
constructor( selection ) {
// content of tick funciton here
}
public addToChart = function (n: number) {
return this;
}
public stop = function () {
return this._stop = true;
}
}
let mychart = function () {
let stop = false;
let chartNew: Chart = new Chart(1);
return chartNew;
};
您可以定义一个接口,即描述函数签名及其属性的接口。根据您的代码,可能是这样的:
interface IChart {
(selection: any): any;
// Use overloading for D3 getter/setter pattern
addToChart(): string; // Getter
addToChart(value: string): IChart; // Setter
}
由于您应该避免任何类似瘟疫的,因此可能需要进一步改进,但这应该足以让您开始。此外,为了允许D3 ish getter/setter模式,您可以在接口声明中使用addToChart
函数
将此接口作为一种类型集成到可重用代码模式中现在变得非常简单:
const mychart = (): IChart => {
// Private value exposed via closure
let value: string|undefined;
const chart = <IChart>((selection) => {
// Private logic
});
// Public interface
// Implementing a D3-style getter/setter.
chart.addToChart = function(val?: string): any {
return arguments.length ? (value = val, chart) : value;
};
return chart;
}
const chart = mychart();
console.log(chart.addToChart()) // --> undefined
chart.addToChart("Add"); // Sets private value to "Add".
console.log(chart.addToChart()) // --> "Add"
constmychart=():IChart=>{
//通过关闭暴露的私人价值
let值:字符串|未定义;
常量图表=((选择)=>{
//私有逻辑
});
//公共接口
//实现一个D3风格的getter/setter。
chart.addToChart=函数(val?:字符串):任意{
return arguments.length?(value=val,chart):值;
};
收益表;
}
const chart=mychart();
console.log(chart.addToChart())/-->未定义
图表.addToChart(“添加”);//将私有值设置为“添加”。
console.log(chart.addToChart())/-->“添加”
查看可执行文件。您可以使用
Object.assign
创建混合类型(具有额外属性的函数),而无需定义专用接口。您可以在原始文件中单独定义函数,这样每个函数都可以有多个签名,如果您想通过this
而不是chart
访问对象,您甚至可以键入this
参数
let mychart = function () {
let isStopped = false;
let value = "";
type Chart = typeof chart;
// Complex method with multiple signatures
function addToChart(): string
function addToChart(newValue: string): Chart
function addToChart(newValue?: string): string | Chart {
if(newValue != undefined){
value = newValue;
chart.stop()
return chart;
}else{
return value;
}
}
// We can specify the type for this if we want to use this
function stop(this: Chart) {
isStopped = true;
return this; // instead of chart, either is usable
}
var methods = {
addToChart,
stop,
// inline function, we can return chart, but if we reference the Chart type explicitly the compiler explodes
stop2() {
isStopped = true;
return chart;
}
};
let chart = Object.assign(function (selection) {
function tick() {
}
return tick;
}, methods);
return chart;
};
let d = mychart();
d("");
d.addToChart("").addToChart();
d.addToChart();
d.stop();
d.stop().addToChart("").stop2().stop()
注释
d
上并查看该类型,它比手工制作的版本要难看得多方法
,而不是内联在对象上。赋值
,因为如果我这样做,编译器会感到困惑this
,则不需要显式键入this
。我演示了如何使用它,只是为了完整起见,使用图表可能更容易,而且它可以确保我们不必处理传入错误的this
的人mychart
键入为任意值。一种情况是,我们在分配给方法的对象中定义的函数中引用图表
我会试试看,然后再打给你。我已经给了你一个向上投票,一旦我在我的代码中测试它,我将接受。你的游乐场示例链接到我在我的OP中发布的示例。抱歉,缓冲区大小有问题,但你可以复制并粘贴我发布的代码作为游乐场的答案。我无法接受此答案,因为它对原始代码的更改太多。我希望在原始代码中添加一个类型,而不是更改原始代码以适应某个类型。值得注意的是,D3社区中似乎很少有人使用ES6类。必须完全重新实现使用ES6类的模式并不是答案。对于任何从我的推特上得知悬赏的人来说,我很确定问题中的普通函数和箭头函数的区别有点像是在转移视线;无论词法范围如何,TypeScript都很难使用这种类型的代码。更大的问题是如何在TS中注释“带有getter和setter的闭包”风格的代码。这非常好,可能是我见过的最接近这种工作方式的代码。但是,重载接口会导致一切中断-请尝试向接口添加以下内容,这将是addToChart的getter版本:
addToChart():string
如果您将两个addToChart方法组合成类似于yScale(scale?:any)的东西:这个|字符串代码>有效,但这似乎扭曲了声明的含义-如果定义了scale
,则返回值将是this
;如果未定义,返回值将为string
。在任何情况下,不提供任何参数都不会导致它返回this
。你比我抢先一步。我只是在我的回答中包含了这一点。。。但是,正如您已经提到的,我对此并不完全满意。@aendrew请看一下编辑,它引入了addToChart
函数的重载,以便更清楚地说明问题。我在尝试复制这一点时,认真地搔了十分钟的头,这是非常明智的-值得注意的const chart=((选择) => {});代码>不等于const chart=(selection)=>{}代码>!无论如何,这是一个很好的答案,它确实帮助我弄清楚这一切到底发生了什么。我会在我有能力的第一时间奖励赏金。这还不错,但我觉得@altocumulus'的回答更为地道和简洁。这也不能真正解决重载函数需要联合返回类型的问题。