fable-compiler / Fable

F# to JavaScript, TypeScript, Python, Rust and Dart Compiler
http://fable.io/
MIT License
2.91k stars 298 forks source link

ts2fable fails with ' TypeError: Cannot read property 'kind' of undefined' #537

Closed jcoder58 closed 7 years ago

jcoder58 commented 7 years ago

Description

ts2fable fails with ' TypeError: Cannot read property 'kind' of undefined'

Repro steps

I'd like to get fable to work with Unreal.js, a Javascript plugin for Unreal Engine 4. The API to UE4 is supplied as d.ts, so I hoped to import it. The d.ts files can be found at https://github.com/ncsoft/Unreal.js/tree/master/Examples/Content/Scripts/typings

The failure below was by running ts2fable _part_0_ue.d.ts

Actual behavior

< TypeError: Cannot read property 'kind' of undefined
<     at getVariables (C:\Users\j\AppData\Roaming\npm\node_modules\ts2fable\ts2fable.js:591:37)
<     at C:\Users\j\AppData\Roaming\npm\node_modules\ts2fable\ts2fable.js:776:36
<     at visitEachNode (C:\Users\j\AppData\Roaming\npm\node_modules\ts2fable\node_modules\typescript\lib\typescript.js:7255:30)
<     at Object.forEachChild (C:\Users\j\AppData\Roaming\npm\node_modules\ts2fable\node_modules\typescript\lib\typescript.js:7412:24)
<     at visitFile (C:\Users\j\AppData\Roaming\npm\node_modules\ts2fable\ts2fable.js:773:8)
<     at Object.<anonymous> (C:\Users\j\AppData\Roaming\npm\node_modules\ts2fable\ts2fable.js:827:20)
<     at Module._compile (module.js:413:34)
<     at Object.Module._extensions..js (module.js:422:10)
<     at Module.load (module.js:357:32)
<     at Function.Module._load (module.js:314:12)

Known workarounds

None

Related information

ts2fable Version 1.22

alfonsogarciacaro commented 7 years ago

Sorry I haven't replied to this before. With the new features added to Typescript it's getting more and more difficult to parse the declarations and keep them in sync so I'm looking for alternative ways to make the bindings at the moment. Suggestions are welcome!

voronoipotato commented 7 years ago

This might be a dumb question but is there no way to create a type provider, similar to the powershell type provider?

alfonsogarciacaro commented 7 years ago

This is indeed possible and I was also considering it, but it's not without challenge. It'd be nice if the type provider could communicate with the typescript server so it could infer type info also from .js files (not only .d.ts declarations), but this would probably require considerable development effort.

Some possible limitations of the type provider vs the parser:

Dessix commented 7 years ago

It could be possible to use pre-existing tools to infer a d.ts from an existing JS file, then use the existing d.ts tooling to handle the loose typings produced. See https://github.com/Microsoft/dts-gen

fsoikin commented 7 years ago

Why doesn't ts2fable just use the TS compiler itself to parse the file?

fsoikin commented 7 years ago

Oh, wait a minute, it actually does. Never mind then. :-)

fsoikin commented 7 years ago

@jcoder58 in this case ts2fable crashes on variable EOrientPositionSelector (line 183):

declare var EOrientPositionSelector = { Orientation:'Orientation',Position:'Position',OrientationAndPosition:'OrientationAndPosition', };

This declaration is actually illegal in a .d.ts file: it is a variable initialization in a typing declaration. This is not allowed. (just think about it: why would you include initialization value for a variable?) If you open this .d.ts file in an IDE with TS support (e.g. VS Code), you'll see an error saying: "Initializers are not allowed in ambient contexts."

From the initialization value, I could speculate that the true intent of this declaration was to indicate the type of the variable to be { Orientation:'Orientation', Position:'Position',OrientationAndPosition:'OrientationAndPosition' } (though I can't think of a use for such type). If this is the case, you should change the equality sign to a colon:

declare var EOrientPositionSelector: { Orientation:'Orientation',Position:'Position',OrientationAndPosition:'OrientationAndPosition' };

This way, both TypeScript and ts2fable will be happy: TypeScript won't produce an error message, and ts2fable will produce F# code like this:

type [<AllowNullLiteral>] EOrientPositionSelectorType =
    abstract Orientation: obj with get, set
    abstract Position: obj with get, set
    abstract OrientationAndPosition: obj with get, set

type [<Erase>]Globals =
    [<Global>] static member EOrientPositionSelector with get(): EOrientPositionSelectorType = jsNative and set(v: EOrientPositionSelectorType): unit = jsNative

P.S. This is not the only such variable initializer in that file. I would guess that this file was originally written for a very old version of TypeScript and never updated.

panesofglass commented 7 years ago

To the best of my (limited) understanding, declare var (or similar variations such as let or const) are not only allowed but necessary in some cases to correctly export values. There are newer and better ways, such as export as namespace, but the old way still needs to be supported, as many declaration files used that when it was the only way.

alfonsogarciacaro commented 7 years ago

Continued in ts2fable repo