Skip to content

Support Sub-set to Super-set casts for Tagged Union #439

Open
@Booksbaum

Description

@Booksbaum
interface Circle {
  kind: "circle";
  radius: number;
}
 
interface Square {
  kind: "square";
  sideLength: number;
}
 
type CircleOrSquare = Circle | Square;

interface Triangle {
  kind: "triangle";
  sideLength: number;
}

type Shape = CircleOrSquare | Triangle;

=>

// [...]
type [<TypeScriptTaggedUnion("kind")>] [<RequireQualifiedAccess>] CircleOrSquare =
    | Circle of Circle
    | Square of Square
    static member inline op_ErasedCast(x: Circle) = Circle x
    static member inline op_ErasedCast(x: Square) = Square x

// [...]

type [<TypeScriptTaggedUnion("kind")>] [<RequireQualifiedAccess>] Shape =
    | Circle of Circle
    | Square of Square
    | Triangle of Triangle
    static member inline op_ErasedCast(x: Circle) = Circle x
    static member inline op_ErasedCast(x: Square) = Square x
    static member inline op_ErasedCast(x: Triangle) = Triangle x

=> 'Shape is superset of CircleOrSquare' is lost

-> Add additional op_ErasedCast to convert from CircleOrSquare to Shape:

    static member inline op_ErasedCast(x: CircleOrSquare) =
        match x with
        | CircleOrSquare.Circle circle -> Shape.Circle circle  
        | CircleOrSquare.Square square -> Shape.Square square

(see #438 (comment))



Maybe an additional conversion from Shape to CircleOrSquare?

Typescript can detect matching subset:

function onCircleOrSquare(cos: CircleOrSquare) {
    console.log("circle or square")
}

function onShape(s: Shape) {
    if(s.kind == "square" || s.kind == "circle") {
        onCircleOrSquare(s)
    }
    else {
        console.log("just shape")
    }
}

In F# maybe some (explicit) cast function?

let asCircleOrSquare (s: Shape): CircleOrSquare option =
    match s with
    | Shape.Circle c -> Some (!^ c) 
    | Shape.Square s -> Some (!^ s)
    | _ -> None

let onCircleOrSquare (cos: CircleOrSquare) =
    printfn "circleOrSquare"
let onShape (s: Shape) =
    printfn "shape"
    match s |> asCircleOrSquare with
    | Some cos -> onCircleOrSquare (cos)
    | None -> printfn "No circle or square"

onShape (!^ circle)
onShape (!^ triangle)

(fable repl)

F# function in Shape module? member on Shape? member on CircleOrShape (probably not -> CircleOrShape sub-set in Shape, not part of Shape in CircleOrShape decl)? Probably needs try in name (tryAs...)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions