簡體   English   中英

盡管 IDE 正確推斷了類型,為什么 Typescript 不推斷泛型類型保護的類型?

[英]Why does Typescript not infer the type for a generic type guard although the IDE infers the type correctly?

Hello, world!

我正在使用 Typescript 和 Webstorm,我正在嘗試使用類型保護,這似乎並不完全正確。

這是一個展示我想要實現的目標的例子。 它也與操場相連

 // 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'; }

問題是:當我在沒有激活“Typescript 語言服務”的情況下使用 Webstorm 時,類型保護會產生正確的類型。 但是,當我嘗試轉換代碼時, tsc拋出錯誤,我不知道為什么。

在我的項目中,我有很多在d.ts文件中自動生成的 Pojo 接口和類,我只想使用一個通用類型保護函數來確定 Pojo 是否是 Klass 對象。 而且我想避免使用as顯式類型轉換。

對我來說同時使用 Pojo 接口和 Klass 類型很重要。

你有什么想法,如何解決這個類型保護問題?

我找到了解決方案🎉🎉!

我可以使用與sequelize相同的技術,在模型屬性類型的類型中使用它。

訣竅是將通用Klass類型分配給correspondsTo接口中的一個假屬性。

操場

 // This is a helper to find the matching class Type interface correspondsTo<Klass> { /* * A dummy variable that doesn't exist on the real object. * This is needed so Typescript can infer the type correctly in the type guard. */ readonly _realKlass?: Klass; } // Use the dummy `_realKlass` attribute to infer the correct type 🎉 function isKlassObject<Pojo> (obj: Pojo) : obj is Pojo extends correspondsTo<any> ? Pojo['_realKlass'] : Pojo { return typeof (obj as any).performAction === 'function'; } // 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('✨'); } } // both type signatures are ok: either only `WizardPojo` function pojoMagic(maybe: WizardPojo ) { if(isKlassObject(maybe)) { // The type is inferred correctly! 🎉 maybe.performMagic(); maybe.performAction(); } } // ... or the intersection type `WizardPojo | RealWizard` function realMagic(maybe: WizardPojo | RealWizard ) { if(isKlassObject(maybe)) { // The type is inferred correctly! 🎉 maybe.performMagic(); maybe.performAction(); } }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM