How do I split a TypeScript class into multiple files?

Solution 1:

Lately I use this pattern:

// file class.ts
import { getValue, setValue } from "./methods";

class BigClass {
    public getValue = getValue;
    public setValue = setValue;

    protected value = "a-value";
}
// file methods.ts
import { BigClass } from "./class";

function getValue(this: BigClass) {
    return this.value;
}

function setValue(this: BigClass, value: string ) {
   this.value = value;
}

This way we can put methods in a seperate file. Now there is some circular dependency thing going on here. The file class.ts imports from methods.ts and methods.ts imports from class.ts. This may seem scary, but this is not a problem. As long as the code execution is not circular everything is fine and in this case the methods.ts file is not executing any code from the class.ts file. NP!

You could also use it with a generic class like this:

class BigClass<T> {
    public getValue = getValue;
    public setValue = setValue;

    protected value?: T;
}

function getValue<T>(this: BigClass<T>) {
    return this.value;
}

function setValue<T>(this: BigClass<T>, value: T) {
    this.value = value;
}

Solution 2:

You can't.

There was a feature request to implement partial classes, first on CodePlex and later on GitHub, but on 2017-04-04 it was declared out-of-scope. A number of reasons are given, the main takeaway seems to be that they want to avoid deviating from ES6 as much as possible:

TypeScript already has too many TS-specific class features [...] Adding yet another TS-specific class feature is another straw on the camel's back that we should avoid if we can. [...] So if there's some scenario that really knocks it out of the park for adding partial classes, then that scenario ought to be able to justify itself through the TC39 process.

Solution 3:

I use this (works in typescript 2.2.2):

class BigClass implements BigClassPartOne, BigClassPartTwo {
    // only public members are accessible in the
    // class parts!
    constructor(public secret: string) { }

    // this is ugly-ish, but it works!
    methodOne = BigClassPartOne.prototype.methodOne;
    methodTwo = BigClassPartTwo.prototype.methodTwo;
}

class BigClassPartOne {
    methodOne(this: BigClass) {
        return this.methodTwo();
    }
}

class BigClassPartTwo {
    methodTwo(this: BigClass) {
        return this.secret;
    }
}