下面的第2部分中的代码(工作示例here)基于第1部分中的代码,但更改为使用箭头功能,它基于Mike Bostock' Toward Resusable Charts中的模式,即返回一个具有其他功能的函数。
如果我尝试在typecript(demo here)中运行第1部分或第2部分中的代码,则表示类型{{1}上的方法addToChart
和stop
不存在}。
(selection: any) => () => void
和addToChart
)?第1部分
stop
第2节
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"
答案 0 :(得分:7)
您可以定义hybrid type,即描述函数签名及其属性的接口。鉴于您的代码,它可能是这样的:
interface IChart {
(selection: any): any;
// Use overloading for D3 getter/setter pattern
addToChart(): string; // Getter
addToChart(value: string): IChart; // Setter
}
既然你应该像瘟疫一样避免any
这可能需要进一步改进,但它应该足以让你开始。此外,为了允许 D3-ish getter / setter模式,您可以在接口声明中overload 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"
查看可执行文件playground demo。
答案 1 :(得分:3)
我想知道你是否可以使用interface / class:
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;
};
答案 2 :(得分:1)
您可以使用Object.assign
创建混合类型(具有额外属性的函数),而无需定义专用接口。您可以单独定义原始内部的函数,因此每个函数可以有多个签名,如果要通过this
而不是{{1}访问对象,甚至可以键入this
参数}}
chart
备注强>
虽然知识产权按预期工作,但如果您将鼠标悬停在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
而不是methods
内联,因为如果我这样做,编译器会感到困惑。
如果您不想在方法中使用Object.assign
,则无需明确键入this
。我展示了如何使用它,只是为了完整性,使用图表可能更容易,它确保我们不必处理传递错误this
的人。
虽然上面的示例有效,但在某些情况下,编译器会放弃推理并将this
的返回值设置为任意。一个这样的情况是我们在分配给mychart
的对象中定义的函数内引用Chart