Reputation: 1012
Reading this tutorial, I see that one way to declare a class in Typescript is to use the class
syntax like so.
class Person {
constructor(name: string) {
this.name = name
}
}
And upon compiling it will generate the following Javascript code.
//Generated by typescript 1.8.10
var Person = (function () {
function Person(name) {
this.name = name
}
return Person;
}());
My question is, is it possible to declare in Typescript a class using the generated Javascript syntax like so...
function Person(name: string) {
this.name = name
}
Upvotes: 1
Views: 692
Reputation: 43078
As an improvement to the already existing answer, you can also do it this way:
interface Person {
name: string;
}
interface PersonConstructor {
new(name: string): Person;
}
const Person: PersonConstructor = function (this: Person, name: string) {
this.name = name;
} as any;
const p = new Person("Alice");
console.log(p.name); // Alice
This way you atleast preserve some type safety if you still care about that stuff.
This way also allows you to define static methods on Person
by first adding them to PersonConstructor
. So you can do:
interface PersonConstructor {
new(name: string): Person;
foo(bar: string): void;
}
And later on do:
Person.foo = (bar: string) => {
console.log(`foo ${bar}`);
}
And call it with Person.foo("something");
Upvotes: 1
Reputation: 327819
It's sort of possible, but not recommended, according to microsoft/TypeScript#2310. According to the TS team, if you're using TypeScript, you should use class
directly. This will compile as-is if you target ES2015 or above, or it will compile down to the function you mentioned if you target ES5.
If you want to ignore the recommendation, you have to do some type annotations and assertions to get the behavior you want, and it will end up leaving a little but of runtime no-op code in the compiled output. And it won't be particularly type safe (if you make a mistake in your typings the compiler will not complain).
First you have to manually define the interface of your class instance, since the compiler can't infer it for you:
interface Person {
name: string;
}
Then you have to give your function a this
parameter so the compiler understands that, inside the implementation of your function, the this
value should be treated as an instance of your class. You should also rename the function out of the way from Person
to something else (like _Person
), because you won't be able to change its type to something new
-able after the fact:
function _Person(this: Person, name: string) {
this.name = name;
}
Finally, you can define Person
as a const
whose value is the same as your renamed function at runtime, but at compile-time you give it a constructor signature:
const Person = _Person as any as new (name: string) => Person;
Now it's set up so that Person
is a function at runtime (not a class
, even if you target ES2015+), but that the compiler sees it as a constructor:
const p = new Person("Alice");
console.log(p.name); // Alice
So, uh, hooray? Fighting against the compiler like this and "winning" probably isn't worth it in any production setting. But it's interesting to see how to do it, I guess.
Okay, hope that helps; good luck!
Upvotes: 2