[英]Typescript Interface With Multiple Dynamic Keys
I have an application that queries a MongoDB database, but is currently only capable of querying a single field in the document:我有一个查询 MongoDB 数据库的应用程序,但目前只能查询文档中的单个字段:
export interface IKeyValue {
[property : string] : any ;
}
export interface IFilter {
[property : string] : IKeyValue;
}
const filter : IFilter = {
"Name" : { $eq : "Bob" }
}
What I want to do is allow IFilter
to allow more than one property:我想要做的是允许
IFilter
允许多个属性:
const filter : IFilter = {
"Name" : { $eq : "Bob" },
"Age" : { $gte : 21 }
}
How can I create a Typescript interface that will allow more than one dynamic key, without reverting to using object
or any
as the type for IFilter
?如何创建一个允许多个动态键的 Typescript 接口,而无需恢复使用
object
或any
作为IFilter
的类型?
How I understand your need is:我如何理解您的需求是:
First of all lets define possible rules we need to filter首先让我们定义我们需要过滤的可能规则
type Rule<T> = { $eq: T } | { $gte: T } // append any other rules you need
I have taken from your example two rules - $eq
and $gte
but by |
我从您的示例中获取了两个规则 -
$eq
和$gte
,但是通过|
you can add others you need.你可以添加其他你需要的。
Second lets define generic Filter
type其次让我们定义通用
Filter
类型
type Filter<Obj> = {
[K in keyof Obj]: Rule<Obj[K]>
}
Our type says - I should have all keys of given object, and for every key I should define a rule which works on the same type as this property has.我们的类型说 - 我应该拥有给定对象的所有键,并且我应该为每个键定义一个规则,该规则适用于与该属性具有的相同类型。 So for property
a: string
the rule needs to be or {$eq: string}
or {$gte: string}
.因此,对于属性
a: string
,规则需要是或{$eq: string}
或{$gte: string}
。
Lets see an example:让我们看一个例子:
// example filter for the User type
type User = {
id: number;
name: string;
}
// create an instance of the filter for the User entity
const userFilter: Filter<User> = {
id: { $gte: 1 }, // rule needs to have value as number
name: {$eq: '2'} // rule needs to have value as string
}
// what if we want to filter by only part of the interface - use Pick utility type
const userFilter2: Filter<Pick<User, 'name'>> = {
name: {$eq: '2'} // only name is needed to be provided
}
Type Filter
is fully type safe, by creating instance of this type we need to define proper keys and proper rules for these keys.类型
Filter
是完全类型安全的,通过创建这种类型的实例,我们需要为这些键定义适当的键和适当的规则。
As an addition you can conditionally say which rules are possible for which types.作为补充,您可以有条件地说明哪些规则适用于哪些类型。 Lets say
$gte
can be applicable only for numbers, but not for other types.可以说
$gte
只能适用于数字,但不适用于其他类型。 You can do so by:你可以这样做:
type Rule<T> = T extends number ? { $eq: T } | { $gte: T } : { $eq: T }
Above definition will prevent from using $gte
for anything other than number.上面的定义将阻止将
$gte
用于数字以外的任何内容。
What I want to do is allow IFilter to allow more than one property
我想做的是让 IFilter 允许多个属性
IFilter
is a type with a string
index signature and already allows multiple properties with string
name type and IKeyValue
value type. IFilter
是一种具有string
索引签名的类型,并且已经允许具有string
名称类型和IKeyValue
值类型的多个属性。 It is just that the IDE/compiler cannot assist with auto completion, as it cannot know, what is inside due to the dynamic way the properties can be added .只是 IDE/编译器不能协助自动完成,因为它不知道,由于可以添加属性的动态方式,里面是什么。
For example your code would be even valid for unknown property names:例如,您的代码甚至对未知的属性名称也有效:
const filterValue = filter["helloWorld"] // IKeyValue
const keyValue = filter["hello"]["World"] // any
I am not sure, what is the best solution here.我不确定,这里最好的解决方案是什么。 If there is a set of fix (potentially optional) property names for
IFilter
like Name
or Age
, maybe a hybrid type with index signature and known properties can be created :如果
IFilter
有一组修复(可能是可选的)属性名称,例如Name
或Age
,则可以创建具有索引签名和已知属性的混合类型:
export interface IFilter {
[property: string]: IKeyValue | undefined;
Name?: IKeyValue;
Age?: IKeyValue;
}
const filter : IFilter = {
"Name": { $eq: "Bob" } // code assist for Name/Age properties
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.