Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript Function returning set of Functions

I'm trying to port the following vanilla JS code to TypeScript to better define return types for all functions. This code exports a single function, resource. When called, resource returns an object containing other functions.

The type signature seems to disappear when using the resource in the Demo class, initialized in the constructor. One approach to this would be to define an interface for resource. However, I can't seem to define an interface for resource without repeating the parameters that are already defined in doThingOne() and doThingTwo(). My current attempts have all lead me to having to duplicate the signatures. How should I approach this to keep things DRY?

function resource(someVar) {

    function doThingOne(p1 = '') {
        return Promise.resolve('thing one ' + someVar + p1);
    }

    function doThingTwo(p1 = '') {
        return Promise.resolve('thing two ' + someVar + p1);
    }

    return {
        doThingOne,
        doThingTwo
    };
}

class Demo {
    resource1;

    constructor() {
        this.resource1 = resource('resource1');
    }
}

const issues = new Demo();
issues.resource1 // no type information for resource1
like image 477
mark Avatar asked Mar 03 '18 15:03

mark


1 Answers

You basically want to type a member as being the result type of a function.

The simplest way to do this, would be to do this would be to let the compiler infer it based on assignment:

class Demo {
    constructor(name: string, public resource1 = resource(name)) {

    }
}

const issues = new Demo("resource1");
issues.resource1 // correct type

If this is not practical, you can get the return type, in one of two ways:

In Typescript 2.8

Use the ReturnType<T> conditional type. (2.8 is unreleased at the time of writing, but will be released in March 2018, you can get it via npm install -g typescript@next)

class Demo {
    public resource1: ReturnType<typeof resource>
    constructor() {

    }
}

Pre 2.8

You can extract the type from the function using a helper function and a dummy variable:

// Dummy function, just used to extract the result type of the function passed as the argument
function typeHelper<T>(fn: (...p:any[]) => T): T{
    return null as T;
}
// Dummy variable, null at runtime, but it's type is inferred as the result of the `resource function
let dummy = typeHelper(resource);

// Create a type definition based on the type of dummy
type resourceReturnType = typeof dummy;


class Demo {
    public resource1: resourceReturnType
    constructor() {

    }
}
like image 164
Titian Cernicova-Dragomir Avatar answered Oct 17 '22 04:10

Titian Cernicova-Dragomir