user3599894
user3599894

Reputation: 69

Type function prototype in typescript

Typescript: How can i add type for function with prototype?

interface Fool {
  greet(): any;
}

function Fool(name: string) {
  this.name = name;
}

Fool.prototype.greet = function() {
  console.log(`Fool greets ${this.name}`);
};

Fool('Joe').greet();
`Property 'greet' does not exist on type 'void'.`;

Upvotes: 4

Views: 6055

Answers (3)

Karol Majewski
Karol Majewski

Reputation: 25800

With this solution, you can use both Fool(name) and new Fool(name).

interface Fool {
  name: string;
  greet(): void;
}

interface FoolConstructor {
  new(name: string): Fool;
  (name: string): Fool;
}

const Fool = function (this: Fool | void, name: string): Fool {
  if (!(this instanceof Fool)) {
    return new Fool(name);
  }

  this.name = name;
  return this;
} as FoolConstructor;

Fool.prototype.greet = function(this: Fool) {
  console.log(`Fool greets ${this.name}`);
};

console.log(
  new Fool('Joe').greet(),
  Fool('Joe').greet()
);

Upvotes: 2

Vitaly Kuznetsov
Vitaly Kuznetsov

Reputation: 1743

If constructing the instance with new suits:

interface Fool {
  name: string;
  greet(): void;
}

interface FoolConstructor {
  new (name: string): Fool;
  (): void;
}

const Fool = function(this: Fool, name: string) {
  this.name = name;
} as FoolConstructor;

Fool.prototype.greet = function() {
  console.log(`Fool greets ${this.name}`);
};

new Fool('Joe').greet();

Upvotes: 4

satanTime
satanTime

Reputation: 13539

UPDATED

In case of node.js and deno you need to compare with undefined instead of Window

interface Fool {
    greet(): any;
}


function Fool(this: any, name: string): Fool {
    if (this === undefined) { // check if it was called statically.
        return new (Fool as any)(name);
    }
    this.name = name;
    return this;
}

Fool.prototype.greet = function () {
    console.log(`Fool greets ${this.name}`);
};

Fool("Joe").greet(); // Fool greets Joe

ORIGINAL

The right way in TS is to use classes instead of prototype. Then you don't need to tackle this problem.

class Fool {
  constructor(public name: string) {}

  greet() {
      console.log(`Fool greets ${this.name}`);
  }  
}

new Fool("Joe").greet(); // Fool greets Joe

If you still want to use prototype, what isn't recommended, you can do a hotfix:

interface Fool {
  greet(): any;
}


function Fool(this: any, name: string): Fool {
  if (this.constructor === Window) { // check if it was called statically.
    return new (Fool as any)(name);
  }
  this.name = name;
  return this;
}

Fool.prototype.greet = function () {
  console.log(`Fool greets ${this.name}`);
};

Fool("Joe").greet(); // Fool greets Joe

Upvotes: 1

Related Questions