考虑下面的代码。
interface IEmployee {
ID: string
Employee: string
Phone: number
Town: string
Email: string
Name: string
}
// Should have all IEmployee properties
let allProps = findOne<IEmployee>("ID = 1234234")
// Should be of type Pick<IEmployee, "Email"| "Phone">
let picked = findOne<IEmployee>("ID = 1234234", ["Email", "Phone"])
如何声明findOne
?是否有可能实现,保持与上面相同的调用代码?
可能的解决方案
使用数组(首选,不工作)
下面的实现不起作用,因为typeof fields[number]
将是Array<keyof T>
function findOne<T>(filter: string, fields: Array<keyof T> =[]): Pick<T,typeof fields[number]> {
return db.select(filter, fields)
}
添加第二个泛型参数(Works)
这是可行的,但不容易阅读
function select<T, K extends Partial<T> = T>(filter: string, fields = Array<keyof K>): K {
return db.select(filter, fields)
}
const props = ["Email", "Phone"] as const
type propsType = Pick<IEmployee, typeof props[number]>
let allProps = select<IEmployee>("Employee: 1234234")
let picked = select<IEmployee, propsType>("Employee: 1234234")
2条答案
按热度按时间nlejzf6q1#
要使其正常工作,需要在两个类型参数中将
findOne()
设置为generic:T
对应于您要查找的基对象类型,K
对应于您要选取的T
中的键的并集。但是有一个问题。你想在调用
findOne()
时手动指定T
,并且你还想让编译器从keys
参数推断K
,而不需要你指定它。不幸的是,Typescript不支持这种类型的部分类型参数推断。或者编译器可以尝试推断所有的类型参数(注意,给K
一个默认类型参数并不能使能部分类型参数推断;你不需要手动指定一个参数的默认值,但是编译器仍然不会为你推断它;它将退回到默认值)。在microsoft/TypeScript#26242上有一个长期的开放特性请求,要求进行部分类型参数推断。
但是,除非这是曾经实现,你将需要围绕它工作。
在这种情况下,我更喜欢的解决方法是curry函数;也就是说,把一个有两个类型参数的函数拆分成一个有一个类型参数的函数,这个函数返回一个有另一个类型参数的函数,就像这样:
现在你可以调用
findOne
并手动指定<T>
,当你调用返回的函数时,K
将被推断出来:在这里有额外的函数调用有点奇怪,但是它起作用了!一旦你开始使用curry函数,你会发现存储中间结果和重用它更容易:
Playground代码链接
v8wbuo2f2#
我不确定这是否是您要找的,但这里有一个findOne的变体。
为了让一切更清楚,我们可以将filter作为一个对象: