Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to inherit? #16

Open
goswinr opened this issue Nov 25, 2023 · 3 comments
Open

How to inherit? #16

goswinr opened this issue Nov 25, 2023 · 3 comments

Comments

@goswinr
Copy link

goswinr commented Nov 25, 2023

TS can inherit interfaces, F# not.
This can be bypassed by creating a separate module that has classes of the same name:

Generated code from Types.Web :

open Fable.Core

/// All classes in this module are empty.
/// They are only used to allow inheriting from types defined as interface.
/// Use this module when you need to inherit from type that is only defined as an interface.
[<RequireQualifiedAccess>] // don't open this. it would shadow the interfaces
module Inheritable =
    

    /// This is NOT a Browser.Types.HTMLElement !
    /// It is just an empty class with the same name.
    /// It used only for inheriting the Browser.Types.HTMLElement interfaces in F#.
    /// Use like: ' type [<AttachMembers>] MyClass() = inherit Inheritable.HTMLElement()'
    /// Then inside the class you can get the current instance via 'base.this' 
    [<Global>]    
    type HTMLElement() = 

        [<Global>]
        member _.this : Browser.Types.HTMLElement = 
            JsInterop.emitJsExpr () "this" 

In user code a Web Component can be made like this:

open Fable.Core

[<AttachMembers>] 
type MyWebComponent() =
    inherit Inheritable.HTMLElement()     
    let myElem = base.this // typed as Browser.Types.HTMLElement not Inheritable.HTMLElement

this gnerates:

  export class MyWebComponent extends HTMLElement {
      constructor() {
          super();
          const myElem = this;
      }
  }

see REPL

@MangelMaxime
Copy link
Contributor

This is an interesting idea. 👍

Could you please provide the TypeScript snippet that correspond to what we are discussing? This is because it helps visualise what the TypeScript code is and how each element should transformed into F#.

Does this means that for each interface we need to generate a corresponding Inheritable type? If yes, is there situation where we don't want to?

If I understand correctly, this means that Browser.Types.HTMLElement can still inherit from mutile interface because it is an interface.

And the Inheritable types are there just for specialisation for example when using Web Component?

When using Web Component (not limited to), is there cases where we want to inherit from several element or is it always only one?

@goswinr
Copy link
Author

goswinr commented Nov 26, 2023

Yes! You are right. This applies to any interface. On your last question, I think JS class can only inherit from one class. (I will add some more snippets later..)

@MangelMaxime
Copy link
Contributor

Something I just thought, is that because of the line JsInterop.emitJsExpr () "this" then generated code is not a pure binding (it contains code).

Luckily using the following:

[<Global>]
member _.this : Browser.Types.HTMLElement = 
	nativeOnly

generates the same code and means that we have a pure binding.

Having pure binding is important because otherwise, you need to include the F# files in the fable folder, which means that Fable will use the sources files instead of the DLL for the compilation. Using the DLL is much faster because the F# compiler has less to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants