[英]Enforce argument to be a keyof other property that extends (or partially) a type
I have a function called updateMany
which accepts a generic type of an entity and allows to update certain data based on the entity and a "by" property which should be a keyof data
.我有一个名为updateMany
的 function ,它接受实体的通用类型,并允许根据实体和“by”属性更新某些数据,该属性应该是 keyof data
。 Something like this:像这样的东西:
function updateMany<Table>() {
return <
Data extends { [column in keyof Table]?: Table[column] },
By extends keyof Data
>(params: {
by: By;
data: Table[];
}) => {};
}
(I wrapped the function inside another function since I wasn't sure how to achieve it in a single function) (我将 function 包裹在另一个 function 中,因为我不确定如何在单个函数中实现它)
Now, everything seems to be working, except the fact that data
has to have all of the properties.现在,一切似乎都在工作,除了data
必须具有所有属性这一事实。 When I try to wrap it inside Partial
, then I can pass to by
properties that doesn't exists in data
.当我尝试将它包装在Partial
中时,我可以通过data
中不存在by
属性传递给它。 I know that my implementation is incorrect, but this is as far as I could get it to what I want.我知道我的实现是不正确的,但这是我能做到的。
My suggestion here would be to write updateMany()
like this:我的建议是这样写updateMany()
:
function updateMany<T>() {
return <
K extends keyof T,
P extends K
>(params: {
by: P;
data: (Pick<T, K> & Partial<T>)[];
}) => { };
}
Both my version and yours use currying to work around the lack of "partial type parameter inference" (as requested in microsoft/TypeScript#26242 ), since there's no way to call a function with multiple type parameters like T
, K
, and P
and have the caller manually specify T
while letting the compiler infer K
and P
.我和你的版本都使用柯里化来解决缺少“部分类型参数推断”的问题(如microsoft/TypeScript#26242中所要求的),因为无法调用具有多个类型参数(如T
、 K
和P
)的 function 和让调用者手动指定T
,同时让编译器推断K
和P
。 Currently in TypeScript it's all or nothing;目前在 TypeScript 中,要么全有,要么全无; you can either manually specify all three, or let the compiler infer all three.您可以手动指定所有三个,也可以让编译器推断所有三个。 Currying sidesteps this by having one function where you specify T
return another function where the compiler infers K
and P
. Currying 通过让一个 function 您指定T
返回另一个 function 来回避这一点,其中编译器推断K
和P
。
Anyway, K
corresponds to the keys present on the elements of data
, and P
corresponds to the key specified in by
.无论如何, K
对应于data
元素上的键, P
对应于 中指定by
键。 I do this with two type parameters instead of just K
for both, since we don't want the compiler to infer that K
is the union of the key from by
and the ones in data
.我使用两个类型参数而不是只使用K
来执行此操作,因为我们不希望编译器推断K
是by
中的键和data
中的键的并集。 Instead we constrain P extends K
so that whatever K
is inferred from data
, we require the key in by
to be in that set.相反,我们约束P extends K
,以便从data
推断出的任何K
,我们都要求 key in by
在该集合中。
Conceptually we would have data
be of type Pick<T, K>[]
and that would be it.从概念上讲,我们将拥有Pick<T, K>[]
类型的data
,就是这样。 But since you said you wanted some better IntelliSense autocompletion for data
, I've intersected Pick<T, K>
with Partial<T>
.但既然你说你想要一些更好的IntelliSense 自动完成data
,我已经将Pick<T, K>
与Partial<T>
相交。 Luckily the compiler seems to use Pick<T, K>
to infer K
to be only those keys actually present in data
entries, while also using Partial<T>
to provide hints for autocompletion.幸运的是,编译器似乎使用Pick<T, K>
来推断K
只是data
条目中实际存在的那些键,同时还使用Partial<T>
来提供自动完成的提示。
Let's see if it works:让我们看看它是否有效:
const updateManyEntities = updateMany<Entity>();;
const X1 = updateManyEntities({ by: "A", data: [{ A: 1 }] }); // okay
const X2 = updateManyEntities({ by: "A", data: [{ A: 1, B: 2, C: 2 }] }); // okay
const X4 = updateManyEntities({ by: "C", data: [{ A: 1, B: 2 }] }); // error!
// ---------------------------> ~~
// Type '"C"' is not assignable to type '"A" | "B"'
const X3 = updateManyEntities({ by: "D", data: [{ A: 1, B: 2, C: 2 }] }); // error!
// ---------------------------> ~~
// Type '"D"' is not assignable to type '"A" | "B" | "C"'
const X5 = updateManyEntities({ by: "D", data: [{ A: 1, B: 2, C: 3, D: 4 }] }); // error!
// ---------------------------> ~~ ----> ~~~~
// Type '"D"' is not assignable to type 'keyof Entity' |
// Object literal may only specify known properties, and 'D' does not exist in type...
Looks good!看起来不错!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.