Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In typescript, how to export the type of a private class without exporting class itself

I have a module in which public method of a public class creates and returns a new instance of a private class. The requirement is that MyClassPrivateHelper must only be instantiated by MyClass.

class MyClassPrivateHelper {
    constructor(private cls: MyClass) {
    }

    public someHelperMethod(arg): void {
        this.cls.someMethod();
    }
}
export class MyClass {
    public createHelper(): MyClassPrivateHelper {  // error here
        return new MyClassPrivateHelper(this);
    }

    public someMethod(): void {
        /**/
    }
}

With this arrangement TypeScript reports error:

[ts] Return type of public method from exported class has or is using private name 'MyClassPrivateHelper'.

My goal is to export just the "type" of the private class without letting an module consuming code be able instantiate it directly. e.g.

const mycls = new module.MyClass();

// should be allowed
const helper: MyClassPrivateHelper = mycls.createHelper();

// should not be allowed
const helper = new module.MyClassPrivateHelper();

I have tried using typeof like so without success.

export type Helper = typeof MyClassPrivateHelper

Maybe I am not understanding how "typeof" works. My questions are:

  • Why export of type using typeof not working?
  • How do I export type without exposing the private class outside module?
like image 796
codneto Avatar asked Mar 20 '18 19:03

codneto


1 Answers

Why export of type using typeof not working?

export type MyInterface = typeof MyClassPrivateHelper

In this example MyInterface is the type of the constructor function but you'd like to export the type of the instances this constructor can produce.

How do I export type without exposing the private class outside module?

Like this:

export type MyInterface = InstanceType<typeof MyClassPrivateHelper>

InstanceType is described briefly here: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html.

Alternatively, I found that the following also works:

type Interface<T> = { [P in keyof T]: T[P] }
export interface MyInterface extends Interface<MyClassPrivateHelper> {}

The Interface type basically copies all public properties from T, which we then use to declare a new interface.

See https://github.com/Microsoft/TypeScript/issues/471#issuecomment-381842426 for more details.

like image 71
Greg Avatar answered Sep 28 '22 17:09

Greg