functionf#argumentstype-annotation

F# function arguments type annotation not working


I want to have a specific type for an argument in a F# function:

type NewType = string*int

let testFunction (arg1:NewType) : NewType =
  ("resultString", 2)

testFunction ("test", 3)

I want the type of the function to be:

NewType -> NewType

But the function type is:

string*int -> NewType

What should I do to enforce the type of the argument arg1 to be "NewType"?


Solution

  • type NewType = string * int is what is called a type abbreviation. It gives a name or alias to another type, but it gets erased during compilation. There is no encapsulation, no new reference and basically no new type at all.

    It can serve as documentation, but F#'s compiler treats the new name and the aliased type the same. This is especially visible if you make a DLL with a public function/method which is using NewType and try to call it from another project - you will see mixed result like in your case.

    This may not be a problem if what you want to achieve is just better readability. If I see let testFunction (arg1:NewType) : NewType = ... in the code, especially on the web like on GitHub, where there are no IntelliSense tooltips, this still gives me pretty good idea what the function takes and returns, even if the "real" type in practice is string * int.

    If you want better type safety, the usual practice is defining a single-case discriminated union which you can combine with pattern matching like this:

    type NewType = NewType of (string * int)
    
    let testFunction (NewType arg1): NewType =
        NewType ("resultString", 2)
    
    testFunction (NewType ("test", 3))
    

    You can read more here, and in other articles from the series: https://fsharpforfunandprofit.com/posts/type-abbreviations/