【问题标题】:Typescript - key/property type guardTypescript - 键/属性类型保护
【发布时间】:2020-02-01 12:49:37
【问题描述】:

我可以创建一个类型保护器,它断言对象中存在(或具有特定类型)的特定属性吗?

我有一个接口Foo

interface Foo {
    bar: string;
    baz: number;
    buzz?: string;
}

现在Foo 类型的对象将有一个可选的属性buzz。我将如何编写一个断言存在 Buzz 的函数: 即

const item: Foo = getFooFromSomewhere();

if (!hasBuzz(item)) return;

const str: string = item.buzz; 

我将如何实现hasBuzz()?。类似于打字机的东西:

function hasBuzz(item: Foo): item.buzz is string {
    return typeof item.buzz === 'string'
}

这样的东西存在吗?

PS:我明白我能做到:

const item = getFooFromSomewhere();

if (typeof item.buzz === 'string') return;

const str: string = item.buzz; 

但我的实际用例要求我有一个单独的函数来断言 buzz 的存在。

【问题讨论】:

  • 使用"buzz" in item?

标签: typescript typeguards


【解决方案1】:

我不喜欢这里现有的答案,因为它们都特定于检查 Foo 对象,但您可以定义一个 hasBuzz 类型保护,它将检查 any 对象以查看它是否有一个buzz 属性。

interface Buzzable {
    buzz: string;
}

function hasBuzz<T extends {buzz?: any}>(obj: T): obj is T & Buzzable {
    return typeof obj.buzz === "string";
}

通过使用通用T 作为输入并返回obj is T &amp; Buzzable 而不仅仅是obj is Buzzable,您在使用hasBuzz 检查时不会丢失任何有关特定接口的信息,例如Foo

如果hasBuzz(item: Foo)true,那么typescript 就知道item 的类型是Foo &amp; Buzzable。在这种情况下,这与Required&lt;Foo&gt; 相同,因为Foo 具有可选的buzz 属性,但您可以检查任何对象。 hasBuzz({}) 完全有效,应始终返回 false

Typescript Playground Link

【讨论】:

    【解决方案2】:

    守卫的重点是让你在不确定类型是什么时缩小范围:

    在您的情况下可能有用的是:

    interface Foo {
        bar: string;
        baz: number;
        buzz?: string;
    }
    
    
    function hasBuzz(item: Foo|Required<Foo>): item is Required<Foo> {
        return typeof item.buzz === 'string'
    }
    
    const f : Foo = {
        bar: 'a',
        baz: 1,
        buzz: 'x'
    };
    
    
    const str : string = f.buzz; // error
    
    if (hasBuzz(f)) {
        const str2 : string = f.buzz; // works
    }
    

    Required 是一个辅助类型,给定另一个类型将返回该类型以及所需的所有属性(自 ts 2.8 起可用)。这会将您的 item 变量缩小为 Required&lt;Foo&gt; 类型的变量

    【讨论】:

      【解决方案3】:

      这应该可行:

      function hasBuzz(item: Foo): item is Foo & Required<Pick<Foo, 'buzz'>> {
          return !!item.buzz
      }
      

      【讨论】:

        【解决方案4】:

        引用属性时可以使用definite assignment assertions

        function hasBuzz(item: Foo): string {
            return item.buzz!;
        }
        

        如果您想在代码中进一步将对象视为肯定有buzz,您可以缩小类型:

        interface DefinitelyBuzzed extends Foo {
            buzz: string;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-12-10
          • 2021-05-17
          • 2020-12-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-22
          • 2019-01-04
          相关资源
          最近更新 更多