3

Function Register is instantiated by calling Register('something'). Typescript says this is only possible if new is used on a void returning function . In this case Register is returning an instance of itself. How should I type this in Typescript?

module Register {

   export function Register(x: string): Instance {
      if (!(this instanceof Register)) {
          return new Register(x)
      }
      this.value = x
   }
   ...

   export interface Instance {
      new(x: string): Instance;
      ...
   }

}
export = Register
6
  • 1
    The answer probably is: "You should not do this in TypeScript", but you should use classes and static methods instead. Commented Oct 10, 2014 at 9:20
  • I hope not. Seems like a legitimate construction to me. Commented Oct 10, 2014 at 9:32
  • Similar questions: How does typescript interfaces with construct signatures work? and IOC for TypeScript Commented Oct 10, 2014 at 12:16
  • @xmojmr As far as I understand the answers to these questions describe constructors that take another constructor as their argument. This seems different from my question that concerns a function with a (string) argument that makes sure it instantiates itself if necessary, when called without new. Commented Oct 10, 2014 at 12:39
  • The linked questions show how to implement class factory pattern where your Register function would be the factory method. If you are looking only for a TypeScript syntax hack needed to make a legacy code base compile then I've misunderstood your intents and the linked questions are not relevant, sorry Commented Oct 10, 2014 at 13:16

2 Answers 2

1

Maybe your example is simplified, and you are trying to achieve something more complex under the hood, but If i understand your code correctly you just want to return an instance of the Register function without the New operator.

The only option i can think of is to trick the TS compiler, and to specify the return type as void, and then in your variables use type any.

module Register {

    export function Register(x: string): void {
        if (!(this instanceof Register)) {
            return new Register(x);
        }
        this.value = x;
    }

    export interface Instance {
        new (x: string): Instance;
        value: string;
    }

}

export = Register;

var rega: any = Register.Register("something");
console.log(rega.value); // something

Update: Since you have a problem with specifying any as the explicit type for each variable, then you could use Object.create() instead of the new operator:

module Register {

    export function Register(x: string): Instance {
        var r = Object.create(Register);
        r.value = x;
        return r;
    }

    export interface Instance {
        new (x: string): Instance;
        value: string;
    }

}

export = Register;

var rega = Register.Register("something");

console.log(rega.value); // something
Sign up to request clarification or add additional context in comments.

4 Comments

The example is simplified indeed. What this construct does is avoid having to use the new keyword to instantiate, so Register.Register('something') would be the same as new Register.Register('something')
Ok cool. I have updated my answer with a hack that could work :)
Thanks, this is how I used it up to now, applying type any. It works, but I hope Typescript can do better. Everywhere you pass Register you need to specify the type any instead of Register.Instance, which is not what you would like.
@ZenCoder I did and this works! And, to add methods to its prototype you now need to write: Register.map = function() {}
0

I suspect you're having the same problem that I ran into (that brought me here).

I was trying to add some TypeScript type definitions (.d.ts) for an existing pure JavaScript (.js) project.

The JavaScript source was a traditional constructor function (with prototype class methods) that detected if it was called without new and did the right thing:

const MyObject = function (options) {
    if (!(this instanceof MyObject)) {
        return new MyObject(options);
    }

    // ...
}

MyObject.prototype.myMethod = function() {
    // Do something...
}

module.exports = MyObject;

My understanding of the "correct" way to add TypeScript types for this kind of JavaScript object is with an interface:

declare interface MyObject {
  /**
   * Constructor interface
   */
  new (options?: Options): this;

  /**
   * Functional interface
   */
  (options?: Options): this;

  /**
   * JSDoc ftw!
   */
  myMethod(): void;
}

// Needed so we can export a variable, not just a type
declare const MyObject: MyObject;

// Since the JavaScript is not exporting a "module" (object with a `default` parameter):
export = MyObject;

Comments

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.