TotPeRo
TotPeRo

Reputation: 6791

Defining TypeScript variable type function or string

I have this interface:

interface IParameters {
    form: number;
    field: string;
    ...
}

I want the formproperty to be number or function and field to be string or function.

I try something like this:

interface IParameters {
    form: number | Function;
    field: string | Function;
    ...
}

I need this because in my code i use this variables like this:

var form = (typeof _oParameters.form === "function" ? _oParameters.form() : _oParameters.form);
var field = (typeof _oParameters.field === "function" ? _oParameters.field() : _oParameters.field);

I don't want change this variable in all my code from string/number to default function and to prevent setting this variables to other types.

but if I try to call one of this two variable like function:

var param:IParameters;
param.form();
...

I get this error:

Cannot invoke an expression whose type lacks a call signature.

but param.form = 12; works.

The only solution that i have found is to declare form and field to any type.

Is other way to define this variable without any type?

Upvotes: 12

Views: 15006

Answers (3)

NielsNet
NielsNet

Reputation: 828

If you try to use the code from seriesOne you will notice, that you cannot assign form (or field) a value that isn't a function. You would get a
Type '{ form: string; }' is not assignable to type 'IParameters'. Types of property 'form' are incompatible. Type 'string' is not assignable to type '() => string'.

I found that using form: (() => string) | string; resolves this problem.

You can try the code at the typescript playground.

Working sample:

    interface IParameters {
        form: (() => string) | string;
    }

    function strFunct(): string {
        return 'Hello TypeScript';
    }

    function test() {
        let paramA: IParameters = {
            form: strFunct
        }

        let paramB: IParameters = {
            form: 'Hello stackoverflow'
        }
    }

    class Foo {
        constructor(param: IParameters) {
            var x = typeof param.form === 'string' ? param.form : param.form();
        }
    }

Upvotes: 20

Matthew Layton
Matthew Layton

Reputation: 42380

Perhaps if you define your union type using a call signature rather than Function, like so...

interface IParameters {
    // form is of type function that returns number, or number literal.
    form: () => number | number;

    // field is of type function that returns a string, or string literal.
    field: () => string | string;
}

class Foo {
    constructor (param: IParameters) {
        var x = typeof param.form === "number" ? param.form : param.form();
        var y = typeof param.field === "string" ? param.field : param.field();
    }
}

Here, I am still checking form and field using typeof, however TypeScript is happy for it to be either a function call, or a value.

Upvotes: 7

Li0liQ
Li0liQ

Reputation: 11264

Upd
That behavior appears to be an issue #3812 with TypeScript.
It is to be fixed as a part of TypeScript 2.0 according to the milestone assigned.

Original answer

You could use instanceof as a type guard like

var field = (_oParameters.field instanceof Function ? _oParameters.field() : _oParameters.field);

Upvotes: 2

Related Questions