Home > Blockchain >  Why does Typescript not infer the type for a generic type guard although the IDE infers the type cor
Why does Typescript not infer the type for a generic type guard although the IDE infers the type cor

Time:11-16

Hello, world!

I am working with Typescript and Webstorm and I am trying to use a type guard, which does not seem to be totally correct.

This is an example to show what I want to achieve. It is also linked in a playground.

// This is a helper to find the matching class Type
interface correspondsTo<Klass> {}

// An interface for a plain javascript object
interface WizardPojo extends correspondsTo<RealWizard>{
    name?: string;
}

// A derivable abstract class 
abstract class Action {

    performAction() {
        console.log('Go!');
    }

}

// A class which implements the plain interface and also inherits a method
class RealWizard extends Action implements WizardPojo {
    name: string;
    
    performMagic() {
        console.log('✨');
    }
}

// This is handled by typescript as expected
function lameMagic () {

    const harry: RealWizard = new RealWizard();
    harry.performMagic();  // correct
    harry.performAction();  // correct


    const harryPojo: WizardPojo = {};
    harryPojo.performMagic() // error: 'performMagic' does not exist -> correct
    harryPojo.performAction() // error: 'performAction' does not exist -> correct

}



// Now here is something not working as expected
function realMagic(maybe: WizardPojo | RealWizard ) {

    if(isKlassObject(maybe)) {

        // Why is that an error?
        maybe.performMagic();
        maybe.performAction();
        const wizard: RealWizard = maybe;

        // Why does not the type guard handle the cast?
        const asWizard = maybe as RealWizard; 
        asWizard.performMagic();
        asWizard.performAction()
    }

}


/*
 I guess this type guard needs some more magic to work correctly
 The weird thing: Webstorm (without Typescript language service setting set)
 recognizes the type correctly
*/
function isKlassObject<Pojo extends correspondsTo<any>> (obj: Pojo)
    : obj is Pojo extends correspondsTo<infer Klass> ? Klass : unknown {
        return typeof (obj as any).save === 'function';
}
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

The thing is: When I use Webstorm without the 'Typescript language service' activated, the type guard results in the correct type. However, when I try to convert the code, tsc throws an error and I don't know why.

In my project I have a lot of those Pojo interfaces and classes which are automatically generated in d.ts files and I want to use just one generic type guard function to determine if a Pojo is a Klass object. And I want to avoid explicit type cast with as.

It is important to me to use both, Pojo interfaces and Klass types.

Do you have an idea, how to fix this type guard problem?

CodePudding user response:

I found a solution

  • Related