【问题标题】:TypeScript async type guard using Promise使用 Promise 的 TypeScript 异步类型保护
【发布时间】:2018-01-01 20:53:28
【问题描述】:

我正在尝试定义一个异步类型保护。我可以同步执行以下操作:

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);
});

Try it here

任何帮助将不胜感激!

【问题讨论】:

  • 它似乎还不是一个功能。也许你可以submit the idea
  • 当使用 tsc 2.0.9 和节点 7.7.3 定位 es6 时,这似乎工作正常。

标签: typescript asynchronous types


【解决方案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);
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-26
    • 2020-11-11
    • 2015-12-19
    • 2020-02-01
    • 2021-01-22
    • 2019-01-04
    • 1970-01-01
    • 2020-07-17
    相关资源
    最近更新 更多