Fable icon indicating copy to clipboard operation
Fable copied to clipboard

[TS] Improve typing for `null`

Open Freymaurer opened this issue 1 month ago • 5 comments

I have the following react component using the "new" f# null feature:

[<ReactComponent>]
let Test(input: string | null) =
    Html.div [
        match input with
        | null -> prop.text "Input is null"
        | notNull ->
            prop.text (notNull + " from F#")
    ]

Which output the following typescript (fable; 5.0.0-alpha.14):

import { ReactElement } from "react";
import React from "react";
import { HtmlHelper_createElement } from "./src/Feliz/Html.tsx";
import { singleton, delay, toList } from "./fable_modules/fable-library-ts.5.0.0-alpha.14/Seq.js";
import { defaultOf } from "./fable_modules/fable-library-ts.5.0.0-alpha.14/Util.js";
import { singleton as singleton_1 } from "./fable_modules/fable-library-ts.5.0.0-alpha.14/List.js";
import { IReactProperty } from "./src/Feliz/Types.tsx";

export function Test(props: { input: string }): ReactElement {
    const input: string = props.input;
    return HtmlHelper_createElement("div", toList<IReactProperty>(delay<IReactProperty>((): Iterable<IReactProperty> => {
        if (input === defaultOf()) {
            return singleton<IReactProperty>(["children", singleton_1("Input is null")] as [string, any]);
        }
        else {
            const notNull: string = input;
            return singleton<IReactProperty>(["children", singleton_1(notNull + " from F#")] as [string, any]);
        }
    })));
}

From a very naive point of view i would have expected something akin to

export function Test(props: { input: string | null }): ReactElement {

and

if (input === null) {

Freymaurer avatar Nov 18 '25 11:11 Freymaurer

Hello,

This is by design.

nullness in F# is checked at compile type, so we don't generate additional type information at runtime.

You can see a discussion about it here: https://github.com/fable-compiler/Fable/pull/4182

MangelMaxime avatar Nov 18 '25 13:11 MangelMaxime

Ah i see. So what is the expected handling for typescript for example?

How could i create something native looking from this? Because option uses the fable type option which does not really look native and null is erased?

Freymaurer avatar Nov 18 '25 13:11 Freymaurer

We don't have an option for generating a native equivalent here. The closest is to use Fable option type.

When F# get support for anonymous DUs, we will probably be able to offer something here.

MangelMaxime avatar Nov 18 '25 16:11 MangelMaxime

@MangelMaxime Can we perhaps have another alpha release? #4182 has been merged, but not released yet, so it may be confusing to explain to people what the expected behavior is, if the generated types they see are different.

ncave avatar Nov 18 '25 18:11 ncave

@ncave I though I had it released.

I just made a new release for Fable 5

MangelMaxime avatar Nov 19 '25 11:11 MangelMaxime