How to write Fable bindings for React component library - f#

Is there any step-by-step guidance available on how to write bindings for a react component library from F#/Fable?
The only example I could find is fable-react-toolbox which makes extensive use of the deprecated KeyValueList attribute.
I am particularly interested in using the BlueprintJS library; I have been able to use ts2fable to generate interface corresponding to the various props defined but have no idea what to do next or where to ask for help!
Any guidance would be greatly appreciated!
Michael

If you already have the props as interfaces you can use the Fable React Helpers to create your component for you.
Let's assume you want to create a wrapper for the Foo component (you already extracted the props to an interface and called it IFooProps) from the react-bar module the code you write would look something like this.
let Foo : ComponentClass<obj> = import "Foo" "react-bar"
let inline foo (props : IFooProps list) elems =
Fable.Helpers.React.from Foo (keyValueList CaseRules.LowerFirst props) elems
The ComponentClass type can be found in the Fable.Import.React module.
A helpful discussion regarding this topic can be found in this GitHub issue https://github.com/fable-compiler/Fable/issues/1044.

Related

Recommended/Canonical format for POM functions

This is more of a style question. When using the POM for Playwright, I've seen 2 different ways of defining classes for export. Was wondering if one is better than the other, or makes any difference in functionality/speed.
So in a POM file, lets call it pomfunctions.js
First way:
exports.PlaywrightDevPage = class PlaywrightDevPage {
constructor section
functions defined here:
}
OR this way:
class PlaywrightDevPage {
constructor section
functions defined here
}
module.exports = { PlaywrightDevPage };
Both are equivalent, since exports points to the same object as module.exports (you just can’t reassign a whole object to export, just its properties - see the Node docs on the exports shortcut) and the module.exports form is using property shorthand syntax (see MDN doc on property definition).
So it really is mostly just a preference, and these Q&A aren’t meant for opinions, so I’ll just say from personal experience that I have more commonly (if not only) seen the module.exports version (so feels like a convention but have no other backing to that), at least for these CommonJS forms, and refrain from stating my opinion on why I like it more as well. I don’t know if there’s a standard though, so believe it’s just up to you!
Hope that helps!

Delay the implementation of interface methods?

I've been programming in F# for some years and there's an "issue" that's been bothering me for some time and I have not been able to solve. It is not a bug, I think it is a design decision, but anyway, the problem is this: is there a way to delay (maybe that's not the correct word for this) the implementation of interfaces?, that is, not implementing them in the initial definition, but later, maybe in the same file after I have implemented a module for the type. I'll explain with a simplified example:
Suppose I have the following data structure:
type 'T MyCollection =
(*type definition*)
interface IEnumerable<'T> with
member this.GetEnumerator () =
(* I don't want to implement it here
because I still don't have the module
with a toSeq function *)
If I implemented the method right there, I would have to also implement all the functions as methods of the type and then the module would be just a "proxy" for calling the methods. This way I'm creating a OO-first data structure and then creating a module (overloaded with type annotations) to allow for a functional-first usage. I would prefer to write a functional-first data structure (cleaner since the type inference can work better) and then create a OO wrapper to allow a better intellisense support for languages like C#. That approach complies with what the design guidelines for F# tells us, but the interfaces can't be implemented anywhere but in the initial definition of the type. That restriction forces me to write the whole data structure with members.
I've been looking for examples and I've found that the list implementation in FSharp.Core list does exactly what I want, but I can't do that, the compiler won't let me.
I'm almost sure that this is a design decision, maybe to avoid encouraging bad practices, I don't know, but I don't consider my wish to be a bad practice. Also I'm well aware of the linear nature of the fsharp compiler.
Please if any of you know how to do what I want, I'll be glad if you tell me. Also, if any of you know why I should not follow this approach I'll be glad to know too. There must be a reason why this is not a problem for anyone else.
Thanks in advance.
I completely agree that this is unfortunate problem. The trick that is used in the source code of 'a list in the F# Core library is to define the implementation of the interface in a type augmentation. The compiler does not complain when you add members to a type in this way, but it says that adding implementation of an interface in this way is deprecated. However, it does not prevent you from doing this. The following compiles fine for me:
open System.Collections
open System.Collections.Generic
type MyCollection<'T> =
{ Data : 'T list }
interface IEnumerable<'T>
interface IEnumerable
let getEnumerator { Data = d } =
(d :> seq<_>).GetEnumerator()
type MyCollection<'T> with
interface IEnumerable<'T> with
member this.GetEnumerator() = getEnumerator this
interface IEnumerable with
member this.GetEnumerator() = (getEnumerator this) :> _
The fact that this is deprecated is a bit unfortunate. I quite like this style and I use it when it makes sense. You can start a discussion about this on F# user voice and perhaps it could be turned back into a normal accepted feature :-)

Using Dart classes from JavaScript

I have a Dart class (foo.dart):
class Foo {
void talk() {
print('Hello');
}
}
After compiling foo.dart to JavaScript, I'd like to be able to use Foo like this:
var foo = new Foo(); // from foo.dart.js
foo.talk() // prints "Hello"
My questions:
Is this currently possible?
If so, how?
If not, what plans, if any, are in place to make it possible?
The dart:js library documentation states:
This library does not yet make Dart objects usable from JavaScript, their methods and proeprties [sic] are not accessible, though it does allow Dart functions to be passed into and called from JavaScript.
That word "yet" offers some hope, but I've found very little on this topic anywhere else.
Edit:
I do realize it's possible to call Dart functions from JavaScript using dart2js. However, what I'm trying to do is somewhat different. I'd like to be able to access all of the functionality of a Dart class from JavaScript.
Due to tree-shaking and minification this is normally not possible. If you have a Dart application (with a main() then you can make a Dart function available to be called from JavaScript (see How to call a Dart function from Javascript? for an example).
As far as I know there are plans to support your requirement but I have no idea about progress or when such a feature might be available.
This is the related project https://github.com/dart-lang/js-interop

Is it possible to extend the User.Identity structure (ASP.Net/MVC) somehow?

Is it possible to store additional data specific to the currently logged on user somehow?
Certainly! If you are not familiar with writing an extension, there are the VB.NET and C# guides on the subject.
You will need to extend the System.Security.Principal.IIdentity interface. As an example:
Declaration:
Imports System.Runtime.CompilerServices
Module Extensions
<Extension()>
Function GetMyCustomProperty(anIdentity As System.Security.Principal.IIdentity, myParameter As Integer) As Object
Return New Object()
End Function
End Module
Usage:
User.Identity.GetMyCustomProperty(4)
NOTES:
The C# code is a fair deal different so it's worth looking at the
guides on how extensions are implemented in general. Running this
code through a VB.NET => C# converter is not enough.
Extensions may only be methods. You may not program custom properties. This will likely mean implementing getter/setter methods if you want property-like behavior.
EDIT:
After seeing your comments, I assume you are doing this to provide a sort of crude functionality similar to a user profile. Consider using a profile provider in concert with any membership you are currently using if you'd like this functionality.

How to implement custom events in F# on the compact framework?

I tried following the example given on MSDN, but my code does not compile on the compact framework. It does compile on the normal framework, though.
type StorageComponent(game) =
inherit GameComponent(game)
let title_storage_acquired_event = new Control.DelegateEvent<StorageEventHandler>()
Error message:
The type 'DelegateEvent' is not defined
Based on the hint from Brian, it looks that the types DelegateEvent<'Delegate> and Event<'Delegate, 'Args> are not supported on .NET Compact Framework. This would mean that you cannot declare an event that uses an explicitly specified delegate type.
However, you can still use the Event<'T> type which creates an event of type Handler<'T> (which is a generic delegate type representing methods with two parameters of types obj and 'T):
type StorageComponent(game) =
inherit GameComponent(game)
let titleStorageAcquiredEvent =
new Event<StorageEventArgs>()
[<CLIEvent>] // If you want to create C# compatible event
member x.TitleStorageAcquired =
titleStorageAcquiredEvent.Publish()
Assuming that the declaration of StorageEventHandler looks like this:
delegate void StorageEventHandler(object sender, StorageEventArgs args);
The example above should create more or less an equivalent code (with the only difference that it uses generic Handler<_> delegate type instead of your own StorageEventHandler).
If you take a look at the code in the CTP
C:\Program Files (x86)\FSharp-2.0.0.0\source\fsharp\FSharp.Core\event.fs
it will offer some clues (I'm guessing NETCF does not have del.DynamicInvoke). It might also offer clues as to what to do instead; I'm not sure, but hopefully someone else will chime in with a full answer.

Resources