是否可以将泛型类型约束为TypeScript中keyof的子集?

时间:2017-01-17 00:22:38

标签: typescript typescript2.0

在TypeScript的当前版本(2.1)中,我可以将泛型类的方法参数约束为泛型类型的属性。

class Foo<TEntity extends {[key:string]:any}> {
    public bar<K extends keyof TEntity>(key:K, value:TEntity[K]) { }
}

当前类型系统是否有可能将关键部分进一步限制为密钥值属于某种类型的子集?

我正在寻找的东西就像这个伪代码一样。

class Foo<TEntity extends {[key:string]:any}> {
    public updateText<K extends keyof TEntity where TEntity[K] extends string>(key:K, value:any) {
        this.model[key] = this.convertToText(value);
    }
}

修改

为了澄清,我添加了一个更完整的例子,说明了我想要实现的目标。

type object = { [key: string]: any };

class Form<T extends object> {
    private values: Partial<T> = {} as T;

    protected convert<K extends keyof T>(key: K, input: any, converter: (value: any) => T[K])
    {
        this.values[key] = converter(input);
    }

    protected convertText<K extends keyof T>(key: K, input: any)
    {
        this.values[key] = this.convert(key, input, this.stringConverter);
    }

    private stringConverter(value: any): string
    {
        return String(value);
    }
}

Demo on typescriptlang.org

convertText会出错Type 'string' is not assignable to type 'T[K]'

鉴于

interface Foo {
    s: string
    n: number
}

编译器可以告诉它这将起作用

this.convert('s', 123, v => String(v));

这不会

this.convert('n', 123, v => String(v));

我希望我可以将convertText方法约束到值为string类型的键,以获得关键参数的类型安全性。

1 个答案:

答案 0 :(得分:4)

有可能(在这里使用非类示例)。以下内容将确保T[P]为字符串。

function convertText<T extends {[key in P]: string }, P extends keyof T>(data: T, field: P & keyof T) {
    // ...
}

我们的想法是将T的类型缩小为P中推断的字段,并设置所需的确切类型,在本例中为string

测试:

let obj = { foo: 'lorem', bar: 2 };
convertText(obj, 'foo');
convertText(obj, 'bar'); // fails with: Type 'number' is not assignable to type 'string'.