Search code examples
syntaxtypescript

TypeScript - Extend type returned by a function


In my code I'm working with my interface that extends an interface of an external library (in order to keep type checks and well, the entire reason for using TypeScript). And generally this works great.

I've now run into a problem where a function from the 3rd party library returns an instance of that base interface, and I need to store it in a variable of my own custom interface, and fill in the remaining properties.

The image with the code and the errors: Code showing the errors (Here is a link to the text version.)

Obviously this problem can be solved by using duck typing and casting, but that feels like it defeats the point of TS altogether, so first thing I'm wondering if there's a syntax to do this.

I've tried:

return { externalFactory(); extraProperty: '' }; // And with comma instead of semi-colon
return externalFactory(): { extraProperty: '' };
return { extraProperty: '' } extends externalFactory();

But my guesses so far have failed. So I'm wondering, is there a syntax or method to do this without losing type safety checks?

You may think extending an object like this would require extra generated code (like extending classes does), but at most it'd be a temporary variable to hold the original object and then add the other properties like:

var temp = externalFactory();
temp.extraProperty = '';
return temp;

And if you're assigning to a variable, that temporary variable isn't even necessary. So it's definitely possible.


Solution

  • This scenario is the very raison d'être of casting (or 'type assertions' as we call them in TypeScript): Someone gives you an expression of type T, and you actually want to treat it as a subtype of T instead.

    function myTypeFactoryAttempt2() : IMyType {
        var theValue = <IMyType>externalFactory();
        theValue.extraProperty = '';
        return theValue;
    }
    

    In this case you're not actually losing any type safety because the type assertion on the second line is itself typechecked -- if you tried to write <number>externalFactory(), you would still get a compile error because the asserted type (number) is not a subtype of the expression (IExternalType).