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!
Playground link to code
classsyntax? typescriptlang.org/play/…