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 型別很重要。
你有什么想法,如何解決這個型別保護問題?
uj5u.com熱心網友回復:
我找到了解決方案????!
我可以使用與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();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/363429.html
