ocsigen / js_of_ocaml

Compiler from OCaml to Javascript.
http://ocsigen.org/js_of_ocaml/
Other
947 stars 185 forks source link

[FEATURE REQUEST] Generate TypeScript declaration file for values exported using Js.export/export_all #1245

Open btj opened 2 years ago

btj commented 2 years ago

Is your feature request related to a problem? Please describe. I waste a lot of time hunting down bugs that result from type errors that I make when I write calls in the JavaScript part of my program of values exported from the OCaml part of my program using Js.export or Js.export_all.

Describe the solution you'd like It would be great if I could use TypeScript to catch those errors as I type. TypeScript needs to know the TypeScript type of the exported values; it would be great if js_of_ocaml would generate a TypeScript declaration file for exported values automatically.

Describe alternatives you've considered Alternatives include:

btj commented 2 years ago

BTW: the project I'm working on is https://github.com/btj/proof-outline-checker

btj commented 2 years ago

For example, suppose I have the following code in mycode.ml:

open Js_of_ocaml
let () = Js.export_all begin
  object%js
    val myJsBool = Js.bool true
    val myNumber = 10
    val myJsString = Js.string "Hello"
    val myOCamlBool = true
    val myOCamlString = "Hello"
    val myOCamlIntList = [1;2;3]
    method myMethod x = x + 1
  end
end

Then running

ocamlfind ocamlc -package js_of_ocaml -package js_of_ocaml-ppx -linkpkg mycode.ml -o mycode.byte
js_of_ocaml --emitTypeScriptDeclarationFile mycode.byte

should create (in addition to mycode.js) the file mycode.d.ts with the following content:

declare var myJsBool: boolean;
declare var myNumber: number;
declare var myJsString: string;
type Bool = {__js_of_ocaml: "bool"};
declare var myOCamlBool: Bool;
type String = {__js_of_ocaml: "string"};
declare var myOCamlString: String;
type IntList = {__js_of_ocaml: "int list"};
declare var myOCamlIntList: IntList;
declare function myMethod(x: number): number;

So, for each OCaml type, a type definition should be generated that binds a unique type name derived from the OCaml type to an object type that is chosen to be highly unlikely to be compatible with any other type that appears in the user's TypeScript program.