2017-07-26 3 views
2

Ich versuche, einen asynchronen Wächter zu definieren. Ich kann das folgende synchron tun:TypeScript async Typ Wache mit Promise

class Foo { 
    public type = 'Foo'; 
} 

// Sync type guard: 
function isFoo(obj: any): obj is Foo { 
    return typeof obj.type !== 'undefined' && obj.type === 'Foo'; 
} 

function useFoo(foo: Foo): void { 
    alert(`It's a Foo!`); 
} 

const a: object = new Foo(); 
if (isFoo(a)) useFoo(a); 

Aber ich bin nicht sicher, wie man das gleiche async tut. Das ist, was ich versucht:

class Bar { 
    public getType =() => new Promise(resolve => { 
     setTimeout(() => resolve('Bar'), 1000); 
    }); 
} 

// Async type guard: 
async function isBar(obj: any): Promise<obj is Bar> { 
    if (typeof obj.getType === 'undefined') return false; 
    const result = await obj.getType(); 
    return result === 'Bar'; 
} 

function useBar(bar: Bar): void { 
    alert(`It's a Bar!`); 
} 

const b: object = new Bar(); 
isBar(b).then(bIsBar => { 
    if (bIsBar) useBar(b); 
}); 

Try it here

Jede mögliche Hilfe würde geschätzt!

+0

Es scheint, es ist noch keine Funktion. Vielleicht könntest du [die Idee einreichen] (https://github.com/Microsoft/TypeScript/issues)? – Paleo

+0

Dies scheint gut zu funktionieren, wenn man es6 mit tsc 2.0.9 und Knoten 7.7.3 anvisiert. –

Antwort

1

Nein, der überwachte Parameter kann nicht von außerhalb des direkten Bereichs der Funktion aufgerufen werden. Sobald Sie also ein Versprechen abgegeben haben, können Sie nicht mehr auf obj wachen. Das klingt wie eine nette Feature-Idee, und wie @Paleo empfiehlt, sollten Sie sie vielleicht einreichen, wenn es noch keine gibt.

Es kann nicht helfen, obwohl; auch wenn Sie eine Art Wächter über Bereiche ausdrücken könnte, könnte der Compiler den Typ wieder verbreitern, da es eine Chance gibt, könnte der Wert mutieren:

class Bar { 
    public getType =() => new Promise(resolve => { 
    setTimeout(() => resolve('Bar'), 1000); 
    }); 
    public barProp: string; // added to distinguish structurally from NotBar 
} 

class NotBar { 
    public getType =() => new Promise(resolve => { 
    setTimeout(() => resolve('NotBar'), 1000); 
    }); 
    public notBarProp: string; // added to distinguish structurally from Bar 
} 

function useBar(bar: Bar): void { 
    alert(`It's a Bar!`); 
} 

function useNotBar(notBar: NotBar): void { 
    alert(`Nope, not a Bar.`) 
} 

var b: Bar | NotBar = new Bar(); 

if (b instanceof Bar) { 
    useBar(b); // narrowed to Bar, no error 
    isBar(b).then(bIsBar => {   
    useBar(b); // error! widened to Bar | NotBar again 
    }) 
} 

Als mögliche Abhilfe können Sie Ihre eigene „Art guard“ erfinden Objekt und übergeben Sie das zurück, obwohl es nicht so angenehm zu verwenden ist:

type Guarded<Y, N = any> = { matches: true, value: Y } | { matches: false, value: N }; 
function guarded<Y, N = any>(v: Y | N, matches: boolean): Guarded<Y, N> { 
    return matches ? { matches: true, value: <Y>v } : { matches: false, value: <N>v }; 
} 

// Async type guard: 
async function isBar<N extends { getType?:() => Promise<any> } = any>(obj: Bar | N): Promise<Guarded<Bar, N>> { 
    if (typeof obj.getType === 'undefined') return guarded(obj, false); 
    const result = await obj.getType(); 
    return guarded(obj, result === 'Bar'); 
} 

isBar(b).then(bIsBar => { 
    if (bIsBar.matches) useBar(bIsBar.value); 
}); 

isBar<NotBar>(b).then(bIsBar => { 
    if (bIsBar.matches) useBar(bIsBar.value); else useNotBar(bIsBar.value); 
}); 
Verwandte Themen