打字稿 - 键/属性类型保护

use*_*467 10 typescript typeguards

我可以创建一个 typeguard,它断言对象中存在特定属性(或具有特定类型)。

IE

我有一个界面Foo

interface Foo {
    bar: string;
    baz: number;
    buzz?: string;
}
Run Code Online (Sandbox Code Playgroud)

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

const item: Foo = getFooFromSomewhere();

if (!hasBuzz(item)) return;

const str: string = item.buzz; 
Run Code Online (Sandbox Code Playgroud)

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

function hasBuzz(item: Foo): item.buzz is string {
    return typeof item.buzz === 'string'
}
Run Code Online (Sandbox Code Playgroud)

这样的东西存在吗?

PS:我知道我可以这样做:

const item = getFooFromSomewhere();

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

const str: string = item.buzz; 
Run Code Online (Sandbox Code Playgroud)

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

Lin*_*ste 7

我不喜欢这里现有的答案,因为它们都特定于检查Foo对象,但是您可以定义一个hasBuzztypeguard 来检查任何对象以查看它是否具有buzz属性。

interface Buzzable {
    buzz: string;
}

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

通过T对输入和返回使用泛型,obj is T & Buzzable而不仅仅是使用泛型,obj is Buzzable您不会丢失有关特定接口的任何信息,例如Foo使用hasBuzz.

如果hasBuzz(item: Foo)true,那么打字稿知道的类型itemFoo & Buzzable。在这种情况下,这与Required<Foo>因为Foo具有可选buzz属性相同,但您可以检查任何对象。 hasBuzz({})是完全有效的,并且应该总是返回false

打字稿游乐场链接


Kel*_*len -1

引用属性时可以使用明确的赋值断言。

function hasBuzz(item: Foo): string {
    return item.buzz!;
}
Run Code Online (Sandbox Code Playgroud)

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

interface DefinitelyBuzzed extends Foo {
    buzz: string;
}
Run Code Online (Sandbox Code Playgroud)