打字稿-钥匙/财产类型保护

时间:2019-10-03 08:23:21

标签: typescript typeguards

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

我有一个接口Foo

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

现在,Foo类型的对象将具有可选的属性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的存在。

4 个答案:

答案 0 :(得分:2)

我不喜欢这里的现有答案,因为它们都是特定于检查const iconContactWay = () => { let [text, component] = ['Contact by Phone Call', <Phone />]; if (preferredContactWay === 'Email') { [text, component] = ['Contact by Email', <Email />]; } else if (preferredContactWay === 'SMS') { [text, component] = ['Contact by SMS', <Sms />]; } return <StyledTooltip title={text}>{component}</StyledTooltip>; }; 对象的,但是您可以定义一个{ key: { text: '...', component: </> }, ... }类型保护程序来检查 any 对象看看它是否具有Foo属性。

hasBuzz

通过使用通用的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 & Buzzable等特定接口进行检查时,不会丢失任何信息。 obj is Buzzable

如果FoohasBuzz,则打字稿会知道hasBuzz(item: Foo)的类型是true。在这种情况下,与item相同,因为Foo & Buzzable具有可选的Required<Foo>属性,但是您可以检查任何对象。 Foo完全有效,应始终返回buzz

Typescript Playground Link

答案 1 :(得分:0)

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

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

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

interface DefinitelyBuzzed extends Foo {
    buzz: string;
}

答案 2 :(得分:0)

警卫的目的是允许您在不确定类型是什么时缩小范围:

您的情况可能有效的方法是:

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<Foo>类型

答案 3 :(得分:0)

这应该有效:

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