panta82
panta82

Reputation: 2721

How to declare something is a class in typescript, the same as using the "class" keyword?

Classes are a bit weird in typescript, in that they seem to be both actual "things" (functions in this case) and typescript types at same time.

Example:

class Test {
  public x: string = 'test';
}

function printX(test: Test) {
  console.log(test.x);
}

function createTest() {
  return new Test();
}

Notice how I can say printX takes an argument of type Test, but also use Test as a value in createTest() method. So the same symbol "Test" is acting as both a value and a type.

How can I recreate the same kind of construct without using the obvious class keyword?

For example:

function makeTestClass() {
  return class Test {
    public x: string = 'test';
  };
}

const Test = makeTestClass();

function printX(test: Test) {
  console.log(test.x);
}

function createTest() {
  return new Test();
}

This code will not compile because typescript will think Test is a value, not a type.

So is there some way I can tell typescript Test is actually the magical dual type/value thing you get using the class keyword?

Upvotes: 1

Views: 61

Answers (1)

aleksxor
aleksxor

Reputation: 8340

I believe the closest one fulfilling your requirements you may get with something like that:

interface Test {
  x: string
}

const Test = function Test(this: Test){
  this.x = 'string' as string
  return this
} as unknown as { new (): Test }

function printX(test: Test) {
  console.log(test.x);
}

function createTest() {
  return new Test();
}

playground link

Here we're defining interface Test (type level) for values of our class' instances. And the constructor function Test (value level) for creating our instances. Since functions do not have constructor signature baked in we have to assert (as unknown as { new (): Test }) typescript that this function still can be used as a constructor with new keyword.

This function still lacks a lot of functionality of a real class. It does not support inheritance and cannot setup private (in typescript sense) members or methods. Also keep in mind that interfaces also cannot fully mimick class instances. As they cannot describe private members or methods too.

Upvotes: 2

Related Questions