是否可以推断通用索引签名的类型?

时间:2019-04-08 14:53:08

标签: typescript

我不会创建用于验证对象的通用函数。 我希望它接受以下签名的选项对象:

export interface ValidationOptions<T, K extends keyof T = keyof T> {
  validators: Map<K, (value: T[K]) => string | null>    
}

我希望能够从K映射到将接受T [K]类型参数的验证函数数组。我的问题是T [K]将解析为T中的每个可能值,而不是给定键的特定值。

下面的代码有望阐明我的意思。

export interface ValidationOptions<T, K extends keyof T = keyof T> {
    validators: Map<K, (value: T[K]) => string | null>    
}

function fooValidator(value: string) {
    if (value === "foo") {
        return "Value can't be foo"
    }

    return null;
}

function isNotTrueValidator(value: boolean) {
    if (!value) {
        return "Value must be true"
    }

    return null;
}

interface ObjectToValidate {
    stringy: string;
    booly: boolean;
}


//(value: T[K]) => string | null will resolve to value: string | boolean here
//Can i make it resolve to the type for the given property instead? 
const options: ValidationOptions<ObjectToValidate> = {
    //This results in an error with strictFunctionTypes enabled
    validators: new Map([
        //How can i 
        ["stringy", fooValidator] 
    ])
}

1 个答案:

答案 0 :(得分:3)

如果意图只是保存基于字符串的键的值,我强烈建议您放弃使用Map。这就是一个普通的旧对象的用途。重要的是,对于TypeScript,基于对象的类型有很多支持,您可以通过mapped type轻松表示validators所期望的行为,如下所示:

export interface ValidationOptions<T> {
    validators: { [K in keyof T]?: (value: T[K]) => string | null }
}

const options: ValidationOptions<ObjectToValidate> = {
    validators: {
        stringy: fooValidator
    }
}

如果由于某种原因您需要继续使用Map,则内置TypeScript typings将不起作用,因为它们的作用更像是一个记录类型,其中每个键都是K,每个值都是V,并且两种类型是独立的。可以代表一种称为ObjectMap的新类型,其类型基于键和值之间的潜在关系,但是要想知道要去哪里,要进行很多类型的调整。

希望有所帮助;祝你好运!