fable-compiler / fable-react

Fable bindings and helpers for React and React Native
MIT License
275 stars 67 forks source link

ofType<'T,'P, 'S> throws away members of the actual type 'T #97

Closed runefs closed 6 years ago

runefs commented 6 years ago

Given a component like this

type Test(intialProps) =
    inherit Component<obj,obj>(intialProps)
    member x.Text with get() = x.props.ToString()
    override x.render() =
        str x.Text

and a helper creation function

let inline test props = ofType<Test,_,_> props [] :?> Test

The below code will compile and run but the result is not as expected

let t  =  test "test text"
printfn "******************* %s ******************" t.Text

Expected result ******************* test text ****************** or that the cast fails Actual resul ******************* undefined ******************

I'm using the latest version of this docker image nojaf/fable

alfonsogarciacaro commented 6 years ago

React helpers like ofType, ofImport, etc (as well as builtins like div, button...) are meant to be uses in a React view function, either nested in another React element (as in div [] [ofType<Test,_,_> props []]) or directly as argument to ReactDom.Render.

According to the signature of ofTypes (and other similar React helpers) the return type of the function is ReactElement and I don't think it's possible to safely cast it to another type.

runefs commented 6 years ago

As I wrote I'd expected that the cast either works and that the methods/properties are then available or that the cast fails, since in all practicalities that is exactly what it does, fails. The result of the above cast is of type ReactElement not 'T

alfonsogarciacaro commented 6 years ago

Sorry, that would be a separate issue, but concurrently down casting in Fable works the same as in Typescript, meaning there are no runtime checks. This is because down casting is mainly used to interact with dynamic objects coming from JS and also because it's difficult to make proper type testing in many cases (like with interfaces or generic types).

runefs commented 6 years ago

Yeah I kind of guessed that after my last comment. I started thinking about how I would implement the checked type cast. And realized that I wouldn't have the information to do that unless the JS object was bloated with a lot of information, that might have other sever issues. Sorry for (another) none bug :)

alfonsogarciacaro commented 6 years ago

No worries! Yes, striking the right balance between good semantics and low overhead in JS runtime is tricky. Actually, you made me realize we need to document better that type casting is not making any runtime checks.

BTW, it's still possible to make type testing in some situations (some primitives and non generic concrete classes).