3

In JavaScript I can do this:

function f() {}
f.prop = "property";

I want this in TypeScript, but with type checking.

Other than classes, what TypeScript pattern can I use to enforce that a function gets a property?

Could I use an interface?

interface functionWithProperty {
    (): any;
    prop: string;
}

This seems to be a valid interface in TypeScript, but how do I implement this interface such that the TypeScript compiler checks that prop is set?

I saw this example:

var f : functionWithProperty = (() => {
    var _f : any = function () { };
    _f.prop = "blah";
    return _f;
}());

But this doesn't work because I can remove _f.prop = "blah"; and everything will still compile. I need to enforce that prop is set.

Community
  • 1
  • 1
Matt York
  • 15,981
  • 7
  • 47
  • 51

2 Answers2

3

I think you need to embrace the object orientation in TypeScript and create a class with properties and functions.

Combining functions and properties as you have in your example is valid JavaScript, but if you are taking the leap into TypeScript you may as well get fully immersed in it.

class MyClass {
    constructor(public myProp: string) {
    }

    myFunc(): string{
        return this.myProp;
    }
}

Update

Disclaimer: I don't recommend doing things this way - as I've said, I recommend using the structural features of TypeScript to organise your code in the most readable way you can.

However, you can define the type of your function if you want to using a type declaration:

var f: { (): void; prop: string; } = (() => {
    var _f : any = function () { 
        alert(_f.prop);
    };
    _f.prop = "blah";
    return _f;
}());

f();

This allows the callers of f to get auto-completion and type checking, but won't result in the contents of f being checked to ensure it complies - because you are "under the hood" at this stage - so you could write this...

var f: { (): void; prop: string; } = (() => {
    var _f : any = undefined;
    return _f;
}());

f();

If you want to get type checking on the definition of f as well as having calls to f checked, you'll need to look at classes.

Fenton
  • 241,084
  • 71
  • 387
  • 401
  • And make it implement that interface: class MyClass implements functionWithProperty to get an error if prop is missing. – joeriks Nov 01 '12 at 05:18
  • Thanks. That's sound advice, but I am explicitly trying to implement this without a class. – Matt York Nov 02 '12 at 04:33
  • @MattYork, then TypeScript maybe not the tool for that. – Ray Cheng Nov 02 '12 at 07:02
  • @MattYork - I have added some detail about how you could do something like you are describing, but it only gives you caller type checking. – Fenton Nov 02 '12 at 09:28
  • As an update you can do it the ways he shows in the second example of the question. – Jon49 Feb 23 '15 at 20:16
2

You can manage this cleanly and with full type information by exploiting declaration merging and structural typing!

interface functionWithProperty {
    (): any;
    prop: string;
}


function MyCoolFunc() {
    return "yay";
}

module MyCoolFunc {
    export var prop: string = "wow";
}

// this will compile without errors, MyCoolFunc implements the
// functionWithProperty interface (structurally)
let x: functionWithProperty = MyCoolFunc;

console.log(x.prop, x());
console.log(MyCoolFunc.prop, MyCoolFunc());

// this would result in a compiler error
// let y: functionWithProperty = console.log;

The compiled javascript will look much like the example you gave in the question, but the TypeScript compiler will know exactly what's going on! Basically, the module declaration of MyCoolFunc gets added in to the function declaration, resulting in a function with a property.

If you want to assert at compile-time that MyCoolFunc implements functionWithProperty correctly, you can have an unexported variable declaration in your module like the one in the example above.

Yourpalal
  • 476
  • 3
  • 11