[英]Typescript generics keyof doesn't match type
I have this interface, that just stores a key of another interface ( modelKey
) and the value of that key ( value
):我有这个接口,它只存储另一个接口的键(
modelKey
)和该键的值( value
):
interface ValueHolder<T, H extends keyof T> {
modelKey: H;
value: T[H];
}
Now I want to store the horsePower
from the following model, with the matching type in a ValueHolder
:现在我想存储来自以下
horsePower
的马力,匹配类型在ValueHolder
中:
interface Car {
id: number;
horsePower?: number;
date: Date;
};
This looks like this:这看起来像这样:
const test: ValueHolder<Car, keyof Car> = {
modelKey: 'horsePower',
value: 1000,
};
At this point no error happens and it would store the value fine.此时不会发生错误,它会很好地存储值。 But you could also pass a value of type
Date
:但您也可以传递
Date
类型的值:
const test: ValueHolder<Car, keyof Car> = {
modelKey: 'horsePower',
value: new Date(),
};
Because for whatever reason the value can accept all types of any key in the model provided:因为无论出于何种原因,该值都可以接受 model 中提供的所有类型的任何键:
(property) ValueHolder<Car, keyof Car>.value: string | number | Date | undefined
How can I make the value
key of the interface ValueHolder
only accepts values of type undefined | number
如何使接口
ValueHolder
的value
键只接受undefined | number
undefined | number
, if you provide the modelKey
horsePower
? undefined | number
,如果你提供的modelKey
horsePower
?
ValueHolder
second generic argument H
allows all keys which in turn leads to allowing all values. ValueHolder
第二个通用参数H
允许所有键,这反过来又导致允许所有值。
You need slightly modify your main utility type to make illegal state unrepresentable.您需要稍微修改您的主要实用程序类型,以使非法 state 无法表示。
Consider this example:考虑这个例子:
type Values<T> = T[keyof T]
type ValueHolder<T> = Values<{
[Prop in keyof T]: {
modelKey: Prop;
value: T[Prop]
}
}>
// type Test = {
// modelKey: "id";
// value: number;
// } | {
// modelKey: "horsePower";
// value: number | undefined;
// } | {
// modelKey: "date";
// value: Date;
// } | undefined
type Test = ValueHolder<Car>
interface Car {
id: number;
horsePower?: number;
date: Date;
};
// ok
const test: ValueHolder<Car> = {
modelKey: 'horsePower',
value: 1000,
};
// error
const test2: ValueHolder<Car> = {
modelKey: 'horsePower',
value: new Date(),
};
See type Test
.请参阅
type Test
。 ValueHolder
creates a union of all allowed values. ValueHolder
创建所有允许值的联合。 It iterates through each key and creates this interface {Prop:{modelKey:P, value:T[P]}}.它遍历每个键并创建此接口 {Prop:{modelKey:P, value:T[P]}}。 Then
Values
obtains each object value {modelKey:P, value:T[P]}
and makes a union of them.然后
Values
获取每个 object 值{modelKey:P, value:T[P]}
并将它们合并。
UPDATE更新
Thanks, works fine!
谢谢,工作正常! What if I want that
T[Prop]
can only be of the type string?如果我希望
T[Prop]
只能是字符串类型怎么办? Is that also possible?这也可能吗?
Yes it is.是的。 There is two ways to achieve it.
有两种方法可以实现它。 You can allow
ValueHolder
only to receive objects where values are strings.您可以只允许
ValueHolder
接收值为字符串的对象。
type ValueHolder<T extends Record<string, string>> = Values<{
[Prop in keyof T]: {
modelKey: Prop;
value: T[Prop]
}
}>
Or, you can check inside iteration whether T[Prop]
is string or not.或者,您可以在迭代内部检查
T[Prop]
是否为字符串。
type ValueHolder<T> = Values<{
[Prop in keyof T]: T[Prop] extends string ? {
modelKey: Prop;
value: T[Prop]
} : never
}>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.