0
votes

Given the following interfaces:

interface Person {
    constructor: Function;
    getFullName(): string;
}

interface PersonConstructor {
    new (firstName: string, lastName: string): Person;
    prototype: Person;
    createPerson(firstName: string, lastName: string): Person;
}

I want to custom-write a class using JS rather than TS, like so:

var Person = (() => {
    function Person(firstName: string, lastName: string) {
        var _firstName = firstName;
        var _lastName = lastName;

        this.getFullName = () => _firstName + " " + _lastName;
    }

    Person.createPerson = (firstName: string, lastName: string): Person => new Person(firstName, lastName);

    return Person;
})();

But I get the following error:

Property 'createPerson' does not exist on type '(firstName: string, lastName: string) => void'

I would also like to be able to use my custom JS as a base class in TypeScript...

class FamousPerson extends Person {

}

But I get this error...

Type '(firstName: string, lastName: string) => void' is not a constructor function type.

How do I get my custom JS to respect my interfaces?

Note: the interfaces follow the same constructor (static interface) pattern adopted in TS 1.4

2

2 Answers

1
votes

You can make it work, but with some use of any:

interface Person {
    getFullName(): string;
}

interface PersonConstructor {
    new (firstName: string, lastName: string): Person;
    prototype: Person;
    createPerson(firstName: string, lastName: string): Person;
}

var Person = (function(): PersonConstructor {
    function Person(firstName: string, lastName: string) {
        var _firstName = firstName;
        var _lastName = lastName;

        this.getFullName = () => _firstName + " " + _lastName;
    }

    (Person as any).createPerson = (firstName: string, lastName: string): Person => new Person(firstName, lastName);

    return Person as any;
})();

(code in playground)

Changes from your code:

  1. Removed the constructor from the Person interface
  2. The actual constructor function closure is declared to return a PersonConstructor
  3. Casting Person to any when adding the createPerson function and when returning it

While this works for your first request, you'll get stuck with the second one, if you intend to override the Person class methods.
For example:

class User extends Person {
    constructor(firstName: string, lastName: string) {
        super(firstName, lastName);

        console.log(this.getFullName());
    }

    getFullName(): string {
        return "user: " + super.getFullName();
    }
}

Creating a new User will log: "first last" instead of "user: first last" and that's because the User.getFullName is defined on the prototype but then in the ctor of Person that is being overridden by the new definition.
It's clearer to see in the compiled js code:

var Person = (function () {
    function Person(firstName, lastName) {
        var _firstName = firstName;
        var _lastName = lastName;
        this.getFullName = function () { return _firstName + " " + _lastName; };
    }
    Person.createPerson = function (firstName, lastName) { return new Person(firstName, lastName); };
    return Person;
})();
var User = (function (_super) {
    __extends(User, _super);
    function User(firstName, lastName) {
        _super.call(this, firstName, lastName);
        console.log(this.getFullName());
    }
    User.prototype.getFullName = function () {
        return "user: " + _super.prototype.getFullName.call(this);
    };
    return User;
}(Person));

(code in playground)

The only way (without going through a lot of trouble) to be able to override methods is if they are implemented on the prototype and not on the instance.
But that will take away the ability to use the "private members" you defined with var, which I assume is the reason you want to do this to begin with.

0
votes
  1. Replace Person.createPerson with `Person['createPerson']

  2. You cannot extends custom-writen class in JS. TypeScript wouldn't understand var Person is a class. Is there any reason you cannot write classes in TS?