我试图定义异步类型保护。我可以同步执行以下操作:
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);
但我不确定如何做同样的异步。这就是我试过的:
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);
});
任何帮助将不胜感激!
答案 0 :(得分:1)
不,您无法从函数的直接范围外访问受保护的参数。所以一旦你回复了承诺,你就不能再保护obj
了。这听起来像一个简洁的功能想法,正如@Paleo建议你应该提交它,如果还没有。
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
})
}
作为一种可能的解决方法,您可以创建自己的“类型保护”对象并将其传回去,尽管使用起来不太令人愉快:
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);
});