Friend class in TypeScript

kamyl picture kamyl · Aug 23, 2017 · Viewed 10k times · Source

In C++ there is something called a friend class. As far as I know, there's no such thing in TypeScript/JavaScript. Is there a way to simulate such behavior of friend class in TypeScript/JavaScript?

To give better context (if needed) of why and what I try to do, I make some small game for fun (and to learn stuff) and try to do this. At the moment I just use public methods and everything works, but I would like to limit accessibility of those methods to just one other class. I use TypeScript, if that helps.

Answer

jcalz picture jcalz · Aug 23, 2017

TypeScript only provides protected and private access modifiers. It does not currently have something like friend or internal.


To get similar effects: if you are packaging your code as a library and emitting .d.ts declaration files for it, you can use the /** @internal */ JSDoc annotation on the properties you don't want outsiders to use, along with specifying the --stripInternal compiler option. This will cause the exported declaration to leave out these properties.


Another way to do something similar is to come up with a public interface which your class implements, and then only export the class as the public interface. For example:

// public interfaces
export interface UnitStatic {
  new(grid: Grid, x: number, y: number): Unit;
}
export interface Unit {
  move(x: number, y: number): void;
}
export interface GridStatic {
  new(): Grid;
  NUM_CELLS: number;
  CELL_SIZE: number; 
}
export interface Grid {
  // public methods on Grid
}

// private implementations
class UnitImpl implements Unit {
  constructor(private grid: GridImpl, private x: number, private y: number) {

  }
  move(x: number, y: number) {
    // ...
  }
}

class GridImpl implements Grid {
  cells: Unit[][] = [];
  constructor() {
    // ...
  }
  static NUM_CELLS = 10;
  static CELL_SIZE = 20;
}

//public exports
export const Unit: UnitStatic = UnitImpl;
export const Grid: GridStatic = GridImpl;

This is tedious but makes it very explicit which parts of your code are meant for outsiders and which are not.


Or, since neither of the above actually prevent people from accessing private/internal info in JavaScript at runtime, you could use an IIFE to really hide those things from outsiders. This might be more annoying to do in TypeScript, though, since it will probably require you to create the above public interfaces in order to typecheck propertly.


So there are some options for you. Hope they help. Good luck!