1

I have this Dir type alias that is a set of 8 cardinal directions, used as an enum:

type Dir = "N" | "NE" | "E" | "SE" | "S" | "SW" | "W" | "NW";

and I have a class Dirs that contains static members for only these values, as well as some utility methods on Dir:

class Dirs {
    public static readonly N: Dir = "N";
    public static readonly NE: Dir = "NE";
    public static readonly E: Dir = "E";
    public static readonly SE: Dir = "SE";
    public static readonly S: Dir = "S";
    public static readonly SW: Dir = "SW";
    public static readonly W: Dir = "W";
    public static readonly NW: Dir = "NW";

    public static unitOffset(dir: Dir): MetroPosition {
        // ...
    }

    public static opposite(dir: Dir): Dir {
        // ...
    }
}

Then, I can use them like this:

Dirs.unitOffset(Dirs.opposite(Dirs.N))

However, I want to change it to chained methods like this, for ergonomics:

Dirs.N.opposite().unitOffset()

In Rust, this is simple (disregarding the different actual values):

enum Dir {N,NE,E,SE,S,SW,W,NW}

impl Dir {
    unitOffset(self) -> MetroPosition {
        // ...
    }
    opposite(self) -> Self {
        // ...
    }
}

// usage
Dir::N.opposite().unitOffset()

Is there a way to give methods to a type alias?

2
  • do you need to use Dirs.N as string like typeof Dirs.N === 'string'? You cannot attach methods to a specific pure JS string Commented Jun 4 at 9:31
  • @AlexanderNenashev no, but I'm serializing this to JSON eventually and having it as a string helps simplify marshalling/unmarshalling. Commented Jun 4 at 13:11

1 Answer 1

2

Unfortunately, Typescript aliases are not objects or classes; They are just type-safe aliases to string literals. It means you can not directly attach behaviour to it (like their own methods) You could try to create a wrapper class with the desired methods, something like this:


type Dir = "N" | "NE" | "E" | "SE" | "S" | "SW" | "W" | "NW";

class DirWrapper {
  constructor(public dir: Dir) {}

  opposite(): DirWrapper {
    const opposites: Record<Dir, Dir> = {
      N: "S", E: "W", S: "N", W: "E", 
     // etc...
    };
    return new DirWrapper(opposites[this.dir]);
  }

  unitOffset() {
  //...
  }
  ... 
}

class Dirs {
  static readonly N = new DirWrapper("N");
  static readonly NE = new DirWrapper("NE");
  static readonly E = new DirWrapper("E");
  static readonly SE = new DirWrapper("SE");
  static readonly S = new DirWrapper("S");
  static readonly SW = new DirWrapper("SW");
  static readonly W = new DirWrapper("W");
  static readonly NW = new DirWrapper("NW");
}

And then you can use it like this:

const offset = Dirs.N.opposite().unitOffset();
Sign up to request clarification or add additional context in comments.

1 Comment

Throwing you an upvote because I've decided to use this approach, but I want to see if there's any other methods of doing this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.