Typescript - ключ / тип свойства guard - PullRequest
2 голосов
/ 03 октября 2019

Могу ли я создать typeguard, который утверждает, что определенное свойство существует (или имеет определенный тип) в объекте.

Т.е.

У меня есть интерфейс 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.

Ответы [ 2 ]

0 голосов
/ 03 октября 2019

Смысл охраны - позволить вам сузиться, когда вы не уверены, какой тип:

Что может сработать в вашем случае:

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 - это вспомогательный тип, который для данного другого типа будет возвращать этот тип со всеми необходимыми свойствами (доступно с версии 2.8). Это сузит вашу переменную item как тип Required<Foo>

0 голосов
/ 03 октября 2019

Вы можете использовать утверждения определенного присваивания , когда ссылаетесь на свойство.

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

Если вы хотите, чтобы объект определенно имел buzz в дальнейшем в коде, выможно сузить тип:

interface DefinitelyBuzzed extends Foo {
    buzz: string;
}
...