The TypeScript transpiler is a useful tool for the development of web applications with a large codebase.
Popular graphics libraries such as Highcharts provides typescript definition files allowing to use their API in a safe way when called from TypeScript code.
It would be awesome if such a definition file was available for plotly.js.
The work consists in creating a TypeScript interface for each object of the public Javascript API.
I've never used typescript before.
Could you point me to good resources or examples of other projects that support typescript (I couldn't find the relevant file in the highcharts repo).
@etpinard take a look at https://github.com/DefinitelyTyped/DefinitelyTyped/
@etpinard the Handbook from the Microsoft website is a good starting point.
http://www.typescriptlang.org/Handbook
You may also be interested by their tutorials and samples:
http://www.typescriptlang.org/Tutorial
http://www.typescriptlang.org/Samples
This blog is also an interesting resource: http://www.johnpapa.net/typescriptpost1/
As xuyang2 said the DefinitelyTyped repo is the place the search for existing TS declaration files.
Here is the folder corresponding to Highcharts: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/highcharts
About IDE support:
Now about the methodology you have two possibilities:
I will suggest to start with approach 1. and to switch to 2. if you think it is useful for your team.
Note that the declarations defined in approach 1 could leveraged when switching to the TS dev, so you won't loose your work.
As a short example if you have a JS config object defining points coordinates, you w'ill define something like that in JS:
var point = { x: 10, y: 20 };
function plotPoint(p) {
// your JS code here
}
plotPoint(point);
To provide a TS type describing this JS object here is what you should have in your "d.ts" file:
interface Point {
x: number;
y: number;
}
declare function plotPoint(p: Point): void
Now if you define your code directly in a TS file, this should be like this:
interface Point {
x: number;
y: number;
}
function plotPoint(p: Point): void = {
// your TS code here
}
var point = <Point>{ x: 10, y: 20 };
plotPoint(point);
Compiling your TS file will result in the JS and .d.ts code above. But as you can see when switch from d.ts to .ts coding, we re-use interfaces defined in the d.ts file. Only the TS code has to be ported from the JS one.
Hope this will be useful.
Best.
@etpinard Videos on Typescript
Thanks for the information! Plotly intends to focus on feature development, bug fixing and performance. Internally we are satisfied with a minimal build system and vanilla JS as this reaches a wide developer and user base. TypeScript is an amazing project that brings static tooling and safety to JS so we have marked this issue as community and are open to any TypeScript definition PRs.
Plotly folks,
I have been working with my own TypeScript definition file for plotly.js for some time now. I would be glad to contribute it to the project. I do not have the bandwidth to get involved with plotly development so I would have to simply hand off the index.d.ts file to you. It accurately describes a UMD library. It "belongs" with you as a versioned artifact. It would be great for you to release it with the distribution. The TypeScript project describes how to integrate the file with your project and NPM. I can't attach the file because the type is not supported. Please shoot me an email at david.geo.[email protected] and I'll send it to you.
Best,
David Geo Holmes https://github.com/geometryzen
BTW. Love Plotly. I'm pushing it into education. See it at https://www.stemcstudio.com (best in Chrome).
@stemcstudio , plotly has starter definitions on DefinitelyTyped. Why not consider creating a pull request for your definitions?
That way, people usings Typings and TypeSearch (npm @Types) can simply use it.
Also check out this: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/7202
cc @chrisgervang
Just opened a PR for the definitions file I've been working on: DefinitelyTyped/DefinitelyTyped#15379
Adding the legend layout: DefinitelyTyped/DefinitelyTyped#17108
As I said in issue board of plotly.js repository, this is not compatible with 3dscatterplot ( try example in official page )
there is no datatype for boxplot
I built a simple react typescript plotlyjs module for the people who looking for simple solution in typescript, check it here
https://github.com/davidctj/react-plotlyjs-ts
@alanpurple, would you mind adding those types to our definition in DefinitelyTyped? Our communities definition isn't complete unfortunately, as there are tons and tons of graphs and components in plotly.
If you don't want to, then everything should work just fine if you use any type since it's just javascript and the plotly library will work without typescript.
I'd be happy to review the PR for you and help where needed.
To make additions:
types compiler option is where that goes, or filesattribute files. I also used any types while testing my comprehension of the source code.@chrisgervang Okay I'll try
I have a Gradle-based TSD generator that parses the plot-schema.json file and generates a TypeScript TSD. I'll attach it here in case anyone finds it useful. If I hear back that it's working for others, I may add it to DefinitelyTyped.
@brian428 This looks great 馃槏
I'm no expert, but I've bumped into limitations of the current index.d.ts on DefinitelyTypes, e.g. I want a table, which is included in your index.d.ts. If there is anything I (or my team) can do to help get this on DefinitelyTyped, that would be awesome 馃檹
Edit: I naively (and erroneously) tried copying your index.d.ts into node_modules. Oops 馃槄 Noob question, but how can I use your declaration instead of (or in addition to) the one currently on DefinitelyTyped?
Edit^2: I modified the index.d.ts from the zip file. It is VERY complete. 25K lines 馃槺 We are testing it. If we get it to work, should we submit a PR to DefinitelyTyped? It will be very breaking though.
Edit^3: We made some more progress, but it is not smooth sailing. Bar, Scatter and Table are working now. In some case, e.g. x: for Bar only accepted number[] so we changed it to number[] | string[], etc. A number of changes like that. I think it might be worth considering adapting this. I'm happy to share our revisions.
@EricForgy sorry, I hadn't checked this thread in a while. I'm sure there are places where things aren't quite right (which will almost always be due to related issues with the Plotly schema JSON that the TSD is generated from, or less common "multiple-type" options for various properties). Since I mainly use the scattergl plots, and not the other plot types, I'm sure it'll take a range of people trying to use it to really squash any lingering problems with the TSD.
Are the long lists of choices, e.g. names of marker symbols (Drawing.symbolList), provided separately or are they missing? I'm thankful for the current (community provided) type definitions, but the "magic strings" are what I most wanted to get from there since I have trouble remembering them & thus frequently make mistakes.
Rather than using union types of literal strings (e.g. 'linear' | 'spline' | 'hv' | 'vh' | 'hvh' | 'vhv'), could we use an enum instead? This helps make those lists accessible so that consuming applications do not need to duplicate them. e.g. One could do something like this:
// definition
export const enum LineShapeType {
Linear = 'linear',
Spline = 'spline',
HV = 'hv',
VH = 'vh',
HVH = 'hvh',
VHV = 'vhv',
}
// ...
'line.shape': LineShapeType;
// ...
// user code
import { LineShapeType } from 'plotly.js';
// ...
const choices = Object.values(LineShapeType);
// ...
Would a PR related to these be welcome? (@chrisgervang, @martinduparc, and other contributors)
FWIW, here's how I'm extracting this currently (somewhat crude, but does the job):
const input = '0|"circle"|100|"circle-open"|200|"circle-dot"|300|"circle-open-dot"|1|"square"|101|"square-open"|201|"square-dot"|301|"square-open-dot"|2|"diamond"|102|"diamond-open"|202|"diamond-dot"|302|"diamond-open-dot"|3|"cross"|103|"cross-open"|203|"cross-dot"|303|"cross-open-dot"|4|"x"|104|"x-open"|204|"x-dot"|304|"x-open-dot"|5|"triangle-up"|105|"triangle-up-open"|205|"triangle-up-dot"|305|"triangle-up-open-dot"|6|"triangle-down"|106|"triangle-down-open"|206|"triangle-down-dot"|306|"triangle-down-open-dot"|7|"triangle-left"|107|"triangle-left-open"|207|"triangle-left-dot"|307|"triangle-left-open-dot"|8|"triangle-right"|108|"triangle-right-open"|208|"triangle-right-dot"|308|"triangle-right-open-dot"|9|"triangle-ne"|109|"triangle-ne-open"|209|"triangle-ne-dot"|309|"triangle-ne-open-dot"|10|"triangle-se"|110|"triangle-se-open"|210|"triangle-se-dot"|310|"triangle-se-open-dot"|11|"triangle-sw"|111|"triangle-sw-open"|211|"triangle-sw-dot"|311|"triangle-sw-open-dot"|12|"triangle-nw"|112|"triangle-nw-open"|212|"triangle-nw-dot"|312|"triangle-nw-open-dot"|13|"pentagon"|113|"pentagon-open"|213|"pentagon-dot"|313|"pentagon-open-dot"|14|"hexagon"|114|"hexagon-open"|214|"hexagon-dot"|314|"hexagon-open-dot"|15|"hexagon2"|115|"hexagon2-open"|215|"hexagon2-dot"|315|"hexagon2-open-dot"|16|"octagon"|116|"octagon-open"|216|"octagon-dot"|316|"octagon-open-dot"|17|"star"|117|"star-open"|217|"star-dot"|317|"star-open-dot"|18|"hexagram"|118|"hexagram-open"|218|"hexagram-dot"|318|"hexagram-open-dot"|19|"star-triangle-up"|119|"star-triangle-up-open"|219|"star-triangle-up-dot"|319|"star-triangle-up-open-dot"|20|"star-triangle-down"|120|"star-triangle-down-open"|220|"star-triangle-down-dot"|320|"star-triangle-down-open-dot"|21|"star-square"|121|"star-square-open"|221|"star-square-dot"|321|"star-square-open-dot"|22|"star-diamond"|122|"star-diamond-open"|222|"star-diamond-dot"|322|"star-diamond-open-dot"|23|"diamond-tall"|123|"diamond-tall-open"|223|"diamond-tall-dot"|323|"diamond-tall-open-dot"|24|"diamond-wide"|124|"diamond-wide-open"|224|"diamond-wide-dot"|324|"diamond-wide-open-dot"|25|"hourglass"|125|"hourglass-open"|26|"bowtie"|126|"bowtie-open"|27|"circle-cross"|127|"circle-cross-open"|28|"circle-x"|128|"circle-x-open"|29|"square-cross"|129|"square-cross-open"|30|"square-x"|130|"square-x-open"|31|"diamond-cross"|131|"diamond-cross-open"|32|"diamond-x"|132|"diamond-x-open"|33|"cross-thin"|133|"cross-thin-open"|34|"x-thin"|134|"x-thin-open"|35|"asterisk"|135|"asterisk-open"|36|"hash"|136|"hash-open"|236|"hash-dot"|336|"hash-open-dot"|37|"y-up"|137|"y-up-open"|38|"y-down"|138|"y-down-open"|39|"y-left"|139|"y-left-open"|40|"y-right"|140|"y-right-open"|41|"line-ew"|141|"line-ew-open"|42|"line-ns"|142|"line-ns-open"|43|"line-ne"|143|"line-ne-open"|44|"line-nw"|144|"line-nw-open"'
const array = input.split('|');
const list = array.reduce((list, item, i, a) => {
// Process even indices (extract pairs)
if (i % 2 === 0) {
const code = parseInt(item, 10);
const name = a[i+1].slice(1, -1); // remove quotation marks
list.push({ code, name });
}
return list;
}, []);
const codes = list.map(x => x.code);
const names = list.map(x => x.name);
console.log(JSON.stringify(list, null, ' '));
Output
[
{
"code": 0,
"name": "circle"
},
{
"code": 100,
"name": "circle-open"
},
{
"code": 200,
"name": "circle-dot"
},
{
"code": 300,
"name": "circle-open-dot"
},
{
"code": 1,
"name": "square"
},
{
"code": 101,
"name": "square-open"
},
{
"code": 201,
"name": "square-dot"
},
{
"code": 301,
"name": "square-open-dot"
},
{
"code": 2,
"name": "diamond"
},
{
"code": 102,
"name": "diamond-open"
},
{
"code": 202,
"name": "diamond-dot"
},
{
"code": 302,
"name": "diamond-open-dot"
},
{
"code": 3,
"name": "cross"
},
{
"code": 103,
"name": "cross-open"
},
{
"code": 203,
"name": "cross-dot"
},
{
"code": 303,
"name": "cross-open-dot"
},
{
"code": 4,
"name": "x"
},
{
"code": 104,
"name": "x-open"
},
{
"code": 204,
"name": "x-dot"
},
{
"code": 304,
"name": "x-open-dot"
},
{
"code": 5,
"name": "triangle-up"
},
{
"code": 105,
"name": "triangle-up-open"
},
{
"code": 205,
"name": "triangle-up-dot"
},
{
"code": 305,
"name": "triangle-up-open-dot"
},
{
"code": 6,
"name": "triangle-down"
},
{
"code": 106,
"name": "triangle-down-open"
},
{
"code": 206,
"name": "triangle-down-dot"
},
{
"code": 306,
"name": "triangle-down-open-dot"
},
{
"code": 7,
"name": "triangle-left"
},
{
"code": 107,
"name": "triangle-left-open"
},
{
"code": 207,
"name": "triangle-left-dot"
},
{
"code": 307,
"name": "triangle-left-open-dot"
},
{
"code": 8,
"name": "triangle-right"
},
{
"code": 108,
"name": "triangle-right-open"
},
{
"code": 208,
"name": "triangle-right-dot"
},
{
"code": 308,
"name": "triangle-right-open-dot"
},
{
"code": 9,
"name": "triangle-ne"
},
{
"code": 109,
"name": "triangle-ne-open"
},
{
"code": 209,
"name": "triangle-ne-dot"
},
{
"code": 309,
"name": "triangle-ne-open-dot"
},
{
"code": 10,
"name": "triangle-se"
},
{
"code": 110,
"name": "triangle-se-open"
},
{
"code": 210,
"name": "triangle-se-dot"
},
{
"code": 310,
"name": "triangle-se-open-dot"
},
{
"code": 11,
"name": "triangle-sw"
},
{
"code": 111,
"name": "triangle-sw-open"
},
{
"code": 211,
"name": "triangle-sw-dot"
},
{
"code": 311,
"name": "triangle-sw-open-dot"
},
{
"code": 12,
"name": "triangle-nw"
},
{
"code": 112,
"name": "triangle-nw-open"
},
{
"code": 212,
"name": "triangle-nw-dot"
},
{
"code": 312,
"name": "triangle-nw-open-dot"
},
{
"code": 13,
"name": "pentagon"
},
{
"code": 113,
"name": "pentagon-open"
},
{
"code": 213,
"name": "pentagon-dot"
},
{
"code": 313,
"name": "pentagon-open-dot"
},
{
"code": 14,
"name": "hexagon"
},
{
"code": 114,
"name": "hexagon-open"
},
{
"code": 214,
"name": "hexagon-dot"
},
{
"code": 314,
"name": "hexagon-open-dot"
},
{
"code": 15,
"name": "hexagon2"
},
{
"code": 115,
"name": "hexagon2-open"
},
{
"code": 215,
"name": "hexagon2-dot"
},
{
"code": 315,
"name": "hexagon2-open-dot"
},
{
"code": 16,
"name": "octagon"
},
{
"code": 116,
"name": "octagon-open"
},
{
"code": 216,
"name": "octagon-dot"
},
{
"code": 316,
"name": "octagon-open-dot"
},
{
"code": 17,
"name": "star"
},
{
"code": 117,
"name": "star-open"
},
{
"code": 217,
"name": "star-dot"
},
{
"code": 317,
"name": "star-open-dot"
},
{
"code": 18,
"name": "hexagram"
},
{
"code": 118,
"name": "hexagram-open"
},
{
"code": 218,
"name": "hexagram-dot"
},
{
"code": 318,
"name": "hexagram-open-dot"
},
{
"code": 19,
"name": "star-triangle-up"
},
{
"code": 119,
"name": "star-triangle-up-open"
},
{
"code": 219,
"name": "star-triangle-up-dot"
},
{
"code": 319,
"name": "star-triangle-up-open-dot"
},
{
"code": 20,
"name": "star-triangle-down"
},
{
"code": 120,
"name": "star-triangle-down-open"
},
{
"code": 220,
"name": "star-triangle-down-dot"
},
{
"code": 320,
"name": "star-triangle-down-open-dot"
},
{
"code": 21,
"name": "star-square"
},
{
"code": 121,
"name": "star-square-open"
},
{
"code": 221,
"name": "star-square-dot"
},
{
"code": 321,
"name": "star-square-open-dot"
},
{
"code": 22,
"name": "star-diamond"
},
{
"code": 122,
"name": "star-diamond-open"
},
{
"code": 222,
"name": "star-diamond-dot"
},
{
"code": 322,
"name": "star-diamond-open-dot"
},
{
"code": 23,
"name": "diamond-tall"
},
{
"code": 123,
"name": "diamond-tall-open"
},
{
"code": 223,
"name": "diamond-tall-dot"
},
{
"code": 323,
"name": "diamond-tall-open-dot"
},
{
"code": 24,
"name": "diamond-wide"
},
{
"code": 124,
"name": "diamond-wide-open"
},
{
"code": 224,
"name": "diamond-wide-dot"
},
{
"code": 324,
"name": "diamond-wide-open-dot"
},
{
"code": 25,
"name": "hourglass"
},
{
"code": 125,
"name": "hourglass-open"
},
{
"code": 26,
"name": "bowtie"
},
{
"code": 126,
"name": "bowtie-open"
},
{
"code": 27,
"name": "circle-cross"
},
{
"code": 127,
"name": "circle-cross-open"
},
{
"code": 28,
"name": "circle-x"
},
{
"code": 128,
"name": "circle-x-open"
},
{
"code": 29,
"name": "square-cross"
},
{
"code": 129,
"name": "square-cross-open"
},
{
"code": 30,
"name": "square-x"
},
{
"code": 130,
"name": "square-x-open"
},
{
"code": 31,
"name": "diamond-cross"
},
{
"code": 131,
"name": "diamond-cross-open"
},
{
"code": 32,
"name": "diamond-x"
},
{
"code": 132,
"name": "diamond-x-open"
},
{
"code": 33,
"name": "cross-thin"
},
{
"code": 133,
"name": "cross-thin-open"
},
{
"code": 34,
"name": "x-thin"
},
{
"code": 134,
"name": "x-thin-open"
},
{
"code": 35,
"name": "asterisk"
},
{
"code": 135,
"name": "asterisk-open"
},
{
"code": 36,
"name": "hash"
},
{
"code": 136,
"name": "hash-open"
},
{
"code": 236,
"name": "hash-dot"
},
{
"code": 336,
"name": "hash-open-dot"
},
{
"code": 37,
"name": "y-up"
},
{
"code": 137,
"name": "y-up-open"
},
{
"code": 38,
"name": "y-down"
},
{
"code": 138,
"name": "y-down-open"
},
{
"code": 39,
"name": "y-left"
},
{
"code": 139,
"name": "y-left-open"
},
{
"code": 40,
"name": "y-right"
},
{
"code": 140,
"name": "y-right-open"
},
{
"code": 41,
"name": "line-ew"
},
{
"code": 141,
"name": "line-ew-open"
},
{
"code": 42,
"name": "line-ns"
},
{
"code": 142,
"name": "line-ns-open"
},
{
"code": 43,
"name": "line-ne"
},
{
"code": 143,
"name": "line-ne-open"
},
{
"code": 44,
"name": "line-nw"
},
{
"code": 144,
"name": "line-nw-open"
}
]
@jacobq I'm not sure if you're referring to the current TSD on DefinitelyTyped, or my new TSD (zip is above). But for my version, the main challenge is that it is generated from the Plotly source code (mainly via plot-schema.json). The TSD has to be generated (IMO), because the changes come too quickly and the API is too vast to try and keep up with it manually. My version, which I think is fairly complete, is over 26,000 lines (including doc comments).
I'm not sure that creating enums for the various "magic strings" will work, because an ambient TSD is a compile-time-only artifact. (If there's a way to export concrete types from a TSD, I'm not aware of it.) But it _might_ be possible to generate a non-TSD "companion" file that could be copied into a project.
I'm not sure if you're referring to the current TSD on DefinitelyTyped, or my new TSD (zip is above).
I had been using what I found on DefinitelyTyped (yarn add -D @types/plotly.js).
The TSD has to be generated (IMO), because the changes come too quickly and the API is too vast to try and keep up with it manually.
I agree. Ideally, plotly.js would define and export these itself to ensure that they're always consistent and to avoid the need for a separate package. In the mean time, generating it programmatically for each plotly.js release seems like a reasonable stop-gap solution.
I'm not sure that creating enums for the various "magic strings" will work, because an ambient TSD is a compile-time-only artifact. (If there's a way to export concrete types from a TSD, I'm not aware of it.) But it _might_ be possible to generate a non-TSD "companion" file that could be copied into a project.
While I don't know all the technical details, I've seen this done in other definition files in DefinitelyType's repo. For example in @types/webcl (try searching the repo for "const enum"; there are a lot of results). Maybe it's not as simple as I imagine, but since string enums are just named string literals they should be functionally the same (i.e. everything happens at compile time).
Just figured I'd update this with a TSD for 1.53.0 if anyone has use for it.
plotly.js.zip
Most helpful comment
Just opened a PR for the definitions file I've been working on: DefinitelyTyped/DefinitelyTyped#15379