4

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'.`;
2
  • 1
    Are you missing new? Commented May 18, 2020 at 10:49
  • Why don't you use a class instead? Commented May 18, 2020 at 12:21

3 Answers 3

4

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();
Sign up to request clarification or add additional context in comments.

Comments

2

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()
);

Comments

1

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

12 Comments

That is not true. You can always use the constructor function pattern. It is less used, but stil valid. Vf the section talking about constructor function in typescriptlang.org/docs/handbook/classes.html. What is needed in the example is only the new keyboard.
What is not true? And where did I say it isn't valid? all js is valid for ts, it's just not the right way.
is it possible run it with ts-node , not in browser ``` ts-node "/Users/vaclav.benes/Git/typescript/typescript_samples/learn/proto.ts" /Users/vaclav.benes/Git/typescript/typescript_samples/learn/proto.ts:17 Fool("Joe").greet(); // Fool greets Joe ^ TypeError: Fool(...).greet is not a function at Object.<anonymous> (/Users/vaclav.benes/Git/typescript/typescript_samples/learn/proto.ts:17:13) )```
for browser you need to use tsc to compile .ts into .js, then you can run it from browser too, TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. You can't run without compilation. ts-node does it on the fly.
For example here typescriptlang.org/play/?target=0#code/… you can see on the right side JS version of TS and you can run this JS version in browser.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.