Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking for function signature

Tags:

typescript

I'm working on a service locator project and I'm expecting functions to be passed in that require a single parameter.

Here's a snippet:

"use strict";

/** Declaration types */
type ServiceDeclaration = Function|Object;

export default class Pimple {

    /**
     * @type {{}}
     * @private
     */
    _definitions: {[key: string]: ServiceDeclaration} = {};

    /**
     * Get a service instance
     * @param {string} name
     * @return {*}
     */
    get(name: string): any {
        if (this._definitions[name] instanceof Function) {
            return this._definitions[name](this);
        }
        return this._definitions[name];
    }
}

However, when I try to compile this I get the following error:

error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'ServiceDeclaration' has no compatible call signatures.

I tried creating a new type:

type ServiceFunction = (container: Pimple) => any;

And tried changing instanceof Function to instanceof ServiceFunction but then I get the following error:

error TS2693: 'ServiceFunction' only refers to a type, but is being used as a value here.

I've looked around but haven't been able to find any examples of checking if a passed in function matches a specified signature.

like image 543
Andrew Shell Avatar asked Feb 27 '17 13:02

Andrew Shell


2 Answers

The simplest solution is to use a variable and let TypeScript infer its type:

    get(name: string): any {
        let f = this._definitions[name]; // here, 'f' is of type Function|Object
        if (f instanceof Function)
            return f(this);              // here, 'f' is of type Function
        return f;                        // here, 'f' is of type Object
    }

As an alternative, it is possible to wrap the condition in an explicit type guard:

function isFunction(f): f is Function {
    return f instanceof Function;
}

A small notice: The type Object | Function is not elegant. You may consider to use a better function type and / or a better object type.

like image 186
Paleo Avatar answered Oct 13 '22 12:10

Paleo


Here is a simpler solution than that of Paleo. Instead of using instanceof Function, you can use typeof f === 'function'. Click here for an example I've created on the TypeScript playground. If you mouse over the input variable in the two if branches, you'll see the result that you want.

like image 26
Huy Nguyen Avatar answered Oct 13 '22 10:10

Huy Nguyen