1

I would like to declare a variable that is one of either values, which in Typescript would look like:



type NamedString = "a" | "b"

// can only be "a" or "b"
const myVar:NamedString = "a"

// throws err when trying to set for anything else:
const myVar:NamedString = "c" // <- Err: Type '"c"' is not assignable to type 'NamedString'.

How would I go about achieving the same functionality in Go?

Peter Toth
  • 678
  • 6
  • 23
  • The only true way to restrict is via a public interface and a private type, you can create two global variables with the few possible values or use a constructor that validates it. You can use enums, but it is possible to assign other values (but no one should do it, in a perfect world) – Tiago Peczenyj Apr 11 '22 at 18:59

2 Answers2

3

I would approach it like that, since you can't really restrict the content of a variable:

type NamedString string

// Constants for equality check.
// E.x: 
// val, err := NamedStringByValue("a")
// val == Astring returs true
const (
   Astring NamedString = "a"
   Bstring = "b"
)

func NamedStringByValue(val string) (NamedString, error) {
    switch val {
    case "a", "b":
        return NamedString(val), nil
    default:
        return "", errors.New("unsupported value")
    }
}

If you don't care about the content of the AString and BString and you just wanna distinguish them, you could make use of iota like that:

type NamedString int

// Plus 1, so that default value (0 for ints) can be returned
// in case of an error.
const (
    AString NamedString = iota + 1
    BString
)

func NamedStringByValue(val string) (NamedString, error) {
    switch val {
    case "a":
        return AString, nil
    case "b":
        return BString, nil
    default:
        return 0, errors.New("unsupported value")
    }
}

koioannis
  • 171
  • 1
  • 7
1

This functionality isn't quite in Go

Your best bet however is making a new type and using typed constants for the values the string can take

You can't get around being able to assign an untyped constant (like "c") to your string as far as I know.

package main

import (
    "fmt"
)

type NamedString string 

const (
    aNamed NamedString = "a"
    bNamed NamedString = "b" 
)

func returnString() string {
    return ""
}

func main() {
    myVar := aNamed
    fmt.Println(myVar)
    
    // Still works due to "d" being an untyped constant
    myVar = "d"
    fmt.Println(myVar)
    
    // Error since "d" is of type string now and not a named string
    myVar = string("d")
    
    // Also error due to the method returning a string and not a named string
    myVar = returnString()
}
questionerofdy
  • 513
  • 3
  • 7