Hacker News new | ask | show | jobs
by the_gipsy 3037 days ago
I used to think that classes get special treatment in typescript, because they both reference a type and a constructor function. But I recently found out that you can do the same by exporting a constructor function and it's type with the same name:

module a:

    export type A = { a: string };
    export const A : () => A = () => { return {a: string}; };
module b:

    import A from './a';
    const a = A(); // a is of type A
This way you can completely ditch classes, and still only import a single type/constructor combo. Not having to use `new` means easier composition and generally going more in the direction of functional programming.
1 comments

This is in no way equal to having a 'class A { ... }' that you'd instantiate with 'new A()'. In module b, the const a will not be of 'type A', but a plain object with signature of '{ a: string }' for which A is an alias. That's very different because a plain object is not an instance - you can't use instanceof, try to console.log() it and an instance of a class and you'll see the difference.
I didn't mean that it's equal to having `class A {...}`. What I said is that you can export a type and a function with the same name, which is as convenient as importing a class, which is also both a type and a constructor function (edit: with prototype).

By "constructor function" I meant a function that constructs an object with a given shape, not a "class instance" or prototyped object. Sorry about not being clear. So no `instanceof`, but you are guaranteed to get correct type checking.

See here [1] for example, if you hover `a` it will tell you it is an `A` not a `{a:string}`.

[1]: https://www.typescriptlang.org/play/#src=type%20MapToProps%3...

Yes, Typescript will tell you that it's of type A, but that's not what happens at runtime - that's what I wanted to say. During runtime it's a plain object that has the aforementioned signature.