我正在寻求实现一个通用函数,该函数接受单个类型参数“ T”,它是一个对象。它使用keyof T
指定函数“ property”的第一个参数。现在我无法工作的部分,我想使用T[typeof property]
的类型来指定函数“值”的第二个参数的类型。
这使我接近理想的用法,
type Person = {
name: string;
age: number;
};
function filter<T>(property: keyof T, value: T[typeof property]) {
return `${property} ${value}`
}
filter<Person>("name", 123);
通过上面的代码,我们对“属性”参数进行了类型检查,将其正确地限制为“名称”或“年龄”。不幸的是,对于value参数,它接受数字或字符串,因此它似乎正在创建所有Person类型的keyof的并集。
有什么想法吗?
答案 0 :(得分:1)
您需要在两个参数之间创建一个关系,毕竟您可能要传递多个键和多个值,为什么编译器会假设value
应该具有在property
参数。
要创建关系,您将需要一个额外的类型参数以将属性表示为文字类型
function filter<T, K extends keyof T>(property: K, value: T[K]) {
return `${property} ${value}`
}
filter<Person, "name">("name", 123); // error
filter<Person, "age">("age", 123); // ok
上述实现的问题是,由于打字稿不支持部分类型推断,因此您必须指定其他类型参数。 (希望issue提出的建议很快就会实现,原定于2018年1月推出,但已经推迟了好几次)
为解决此不便,我们可以创建一个函数,该函数返回一个函数并在第一个调用中修复T
参数,并在第二个调用中推论K
function filter<T>() {
return function <K extends keyof T>(property: K, value: T[K]) {
return `${property} ${value}`
}
}
filter<Person>()("name", 123); // error
filter<Person>()("age", 123); // ok
或者根据您打算对filter
进行的操作,可以为函数保留两个类型参数,并将返回类型用作推断T
的源:
function filter<T, K extends keyof T>(property: K, value: T[K]) {
return `${property} ${value}` as IFiler<T>
}
type IFiler<T> = string & { _isFilterFor: T }
class Query<T> {
addFilter(f: IFiler<T>) {
}
}
var q = new Query<Person>();
// T will be inferred to Person in filter because we assign in to a parameter expecting IFilter<Person>
q.addFilter(filter('age', "")) //error
q.addFilter(filter('age', 12)) //ok
// Same as above but assigning to a variable:
var f: IFiler<Person> = filter('age', 12);
var f2: IFiler<Person> = filter('age', "12");
答案 1 :(得分:1)
通过这种方式,您不必更改代码
type Fn<T> = <K extends keyof T>(prop: K, value: T[K]) => string;
function filter(property: string, value: any) {
return `${property} ${value}`;
}
type Person = {
name: string;
age: number;
};
const result = (filter as Fn<Person>)("name", 123);