The code in section 2 below (working example here) is based on the code in section 1 but changed to use arrow functions, and it is based on Mike Bostock's pattern in Toward Resusable Charts, namely returning a function that has other functions on it.
If I try to run either the code in section 1 or 2 in typescript (demo here) it says the methods addToChart
and stop
do not exist on type (selection: any) => () => void
.
addToChart
and stop
in this case) added to the returned function?section 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"
section 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"
You can define a hybrid type, i.e. an interface describing both the function's signature as well as its properties. Given your code it could be something like this:
interface IChart {
(selection: any): any;
// Use overloading for D3 getter/setter pattern
addToChart(): string; // Getter
addToChart(value: string): IChart; // Setter
}
Since you should avoid any
like the plague this might need some further refinement, but it should be enough to get you started. Furthermore, to allow for a D3-ish getter/setter pattern you can overload the addToChart
function in the interface declaration.
Integrating this interface as a type in your reusable code pattern now becomes pretty straightforward:
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"
Have a look at the executable playground demo.
I was wondering if you could use 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;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With