简体   繁体   中英

How to implement prototype-less constructors in Typescript?

Is there any way to replicate the following JS pattern in TS with type-safety?

function InputStream(input) {
    var pos = 0, line = 1, col = 0;
    return {
        next  : next,
        peek  : peek,
        eof   : eof,
        croak : croak,
    };
    function next() {
        var ch = input.charAt(pos++);
        if (ch == "\n") line++, col = 0; else col++;
        return ch;
    }
    function peek() {
        return input.charAt(pos);
    }
    function eof() {
        return peek() == "";
    }
    function croak(msg) {
        throw new Error(msg + " (" + line + ":" + col + ")");
    }
}

If I add type-hints, I get this:

function InputStream(input: string) {
    var pos = 0
    var line = 1
    var col = 0

    return {
        next,
        peek,
        eof,
        croak
    }

    function next(): string {
        var ch = input.charAt(pos++);
        if (ch == "\n") line++, col = 0; else col++;
        return ch;
    }

    function peek(): string {
        return input.charAt(pos);
    }

    function eof(): boolean {
        return peek() == "";
    }

    function croak(msg):string {
        throw new Error(`${msg} (${line}:${col})`);
    }
}

TS will infer the interface of the returned object, so working with an InputStream is type-safe - so far, so good.

My problem is, there doesn't seem to be any way to type-hint an argument as an instance of than interface?

For example (of course) this doesn't work:

function TokenStream(input: InputStream) {
    // ...
}

Is there any way to type-hint the input argument as the return-type of the InputStream function?

I mean, short of explicitly declaring the interface, which seems redundant, given that it's able to infer the interface.

Of course, I could port it to a real class as well - which seems more "correct", but makes code like this extremely verbose.

Is there some other way to achieve something similar, perhaps with modules? I've noticed that modules are able to call functions declared in the module without qualifying with this , and have often wished that were possible with class methods and parent classes, but the TS team turned down that request.

You really want to type that InputStream return value if you need its type somewhere else, it's also good documentation. What you are asking for is some kind of metadata like "give me the type returned by that function", I don't think typescript has that kind of capabilities.

Inference is best left for small lambda functions imo.

For reference, you can do something like:

const input = InputStream('abcd')

function TokenStream(input2: typeof input) {

}

But you need an actual value to type the argument of the second function, which is weird and probably not what you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM