动态类型保护函数

Dynamic type guard functions

我想创建一个类型保护函数来检查对象中的特定键是否具有例如一个 string 值。如果我知道键名,这就很容易了:

const data: object = { a: 'one', b: 'two', c: 'three' };

function hasStringKeyA(data: any): data is { a: string } {
    return typeof data.a === 'string';
}

if (hasStringKeyA(data)) {
    console.log(data.a);
}

但是当我需要检查更多密钥时,这就变得混乱了:

if (hasStringKeyA(data) && hasStringKeyB(data)) {
    console.log([ data.a, data.b ].join(', '));
}

我想做的是:

if (hasStringKeys(data, ['a', 'b', 'c'])) {
    console.log([ data.a, data.c, data.b ].join(', '));
}

但是我想不出如何编写可以通过这种方式进行参数化的类型保护函数。这是一个无效的糟糕尝试:

function hasStringKeys <K extends string[]> (data: any, keys: Keys): data is { [ k: typeof K ]: string } {
    for (const key of keys) {
        if (typeof data[key] !== 'string') {
            return false;
        }
    }
    return true;
}

这可能吗?怎么样?

你很接近。我会使用类型参数来捕获项目的字符串文字类型,而不是整个字符串数组。并且您需要使用映射类型而不是索引签名,您可以自己编写 ({ [ k in K ]: string }),但预定义的 Record 类型也应该可以工作:

const data: object = { a: 'one', b: 'two', c: 'three' };

if (hasStringKeys(data, ['a', 'b', 'c'])) {
    console.log([ data.a, data.c, data.b ].join(', '));
}

function hasStringKeys <K extends string> (data: any, keys: K[]): data is Record<K, string> {
    for (const key of keys) {
        if (typeof data[key] !== 'string') {
            return false;
        }
    }
    return true;
}

Playground Link