-
Notifications
You must be signed in to change notification settings - Fork 300
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 write bindings for errors in Fable 3? #2492
Comments
This is a good question... I don't really know 😅 My first thought is we could include an type Error =
[<Emit("$0.message")>] abstract Message: string
[<Emit("$0.stack")>] abstract StackTrace: string However, this won't work if you want to capture the exception in a try catch. In that case, we do need to inherit from type [<Erase; AllowNullLiteral; AbstractClass>] DatabaseError =
inherit System.Exception
abstract code: string option
let test() =
try
"foo"
with
| :? DatabaseError as e -> e.Message + (defaultArg e.code "0")
| e -> e.Message Now this compiles. The only issue is Fable won't do type testing with erased types, looking at the generated code we realize the export function test() {
let e, e_1;
try {
return "foo";
}
catch (matchValue) {
return (e = matchValue, e.message + defaultArg(e["Test.DatabaseError.get_code"](), "0"));
}
} To have actual type testing, instead of type [<ImportMember("my_library"); AllowNullLiteral; AbstractClass>] DatabaseError =
inherit System.Exception
abstract code: string option
let test() =
try
"foo"
with
| :? DatabaseError as e -> e.Message + (defaultArg e.code "0")
| e -> e.Message // js
export function test() {
let e, e_1;
try {
return "foo";
}
catch (matchValue) {
return (matchValue instanceof DatabaseError) ? ((e = matchValue, e.message + defaultArg(e.code, "0"))) : ((e_1 = matchValue, e_1.message));
}
} |
Hum, I didn't know of the last option. It seems to tick all the features I needed. I will use it today and close this issues if everything seems to be working as expected. Also, thank you for showing that let isDatabaseError (error : obj) : bool =
emitJsExpr (error, PgProtocol.DatabaseError) """$0 instanceof $1""" No I am not at all abusing |
Well, type testing only works here because we use a concrete (imported) type, so your solution is indeed necessary when using interfaces as it's often the case in bindings. There was a proposal to add a special attribute for type testing of interfaces in bindings. I closed it because if lack of feedback but we could revisit it #2437 (comment) |
I think adding the special attributes could be a nice addition to Fable. That's true that in Elmish/React application we don't seems to often need this kind of type testing. However, when writing back-end code and when you want to handle exception error coming from libraries it comes handy. And it would improve the interop feature of Fable. 😉 It would also, makes case like the one I encountered with |
Seems like @alfonsogarciacaro's comment reiterates what we talked about in #2353. IMHO, this approach makes it much easier to understand what the F# bindings actually represent on the JS side. For example, no more values of an |
@inosik Thank you for the head I forgot about that discussion. I will go back to it when I have the time again for it. I started a discussion on Glutinum project so I can keep track of the "most interesting" discussions that happened around this subject. |
A helper like this one could make sense, though. In JS, errors don't necessarily inherit from let (|Error|_|) (exn : exn) =
match box exn with
| :? 'a as err-> Some err
| _ -> None
// Usage:
let f () =
try
JSLib.somethingThatMightThrowAString ()
with
| Error (err : string) ->
printfn "%s" err |
This works better: open System
open Fable.Core
let (|Error|_|) (exn : exn) =
Some (box exn)
// Usage:
let f () =
try
JSLib.somethingThatMightThrowAString ()
with
| Error (:? string as err) ->
printfn "%s" err |
Ups, I forgot about that discussion too. In fact, I think I originally missed this comment so I've posted a reply to it 😅 BTW, I didn't know you could use active patterns in try .. with either. I agree it's a great solution for the cases where you cannot inherit from Error/exn. Following the discussion of how we can improve the bindings, I think I should restrain myself from adding more hacks like
Do you agree with any of them or have any other idea to make a language suggestion. |
|
This could be bypassed by creating a separate module that has classes of the same name as the interface. see: |
Description
This issue a is a follow up from this discussion: fable-compiler/ts2fable#351 (comment)
I am encountering a problem while working with bindings that contains Errors in JavaScript. In Fable 3 (or was it Fable 2?), a decision has been made to use
System.Exception
to represents JavaScript errors but this seems to cause a problem when working on bindings.It seems like we can't inherit from
System.Exception
without addingAsbtractClass
but adding this attributes makes Fable generates an invalid code in the case of the binding.@alfonsogarciacaro What is the correct solution for writing bindings for a JavaScript error ?
REPL
Related information
The text was updated successfully, but these errors were encountered: