简体   繁体   中英

Typescript generics and functions as class attribute type

I have the following code:

class Test<T> {
    value: T | (() => T);

    determineValue(): T {
        if (typeof this.value === 'function') {
            return this.value();
        }
        return this.value;
    }
}

The compiler gives me an error in the line with the call return this.value() :

error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '(() => T) | (T & Function)' has no compatible call signatures.

I don't know what exactly is wrong here. How can I make sure that the value is either of type T or a function return a value with type T .

In the moment I have a workaround, which (I think) is not pretty nice:

return (<() => T>this.value)();

Can someone help me? Thank you! :-)

Your code is in fact unsound if the caller sets T to a function type, for example, T = (x: number) => number , and passes a value of type T , ie, a function that requires a single argument. Your code will try to call this function with no arguments.

You can give the compiler a hint that you don't intend T to be a function type by constraining T by a mapped type that has the same properties but no call signatures. That is, you would change the declaration of class Test to:

class Test<T extends { [P in keyof T]: T[P] }> { /* ... */ }

Then the error should go away. However, the compiler won't stop you from actually instantiating T with a function type, because a function type does extend the same type with the call signatures removed, so be careful. (So I'm surprised the technique above works to remove the error. Arguably the lack of an error might be a bug. If the bug gets fixed, I guess you just go back to your current workaround.)

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