【问题标题】:Typescript Interface With Multiple Dynamic Keys具有多个动态键的打字稿界面
【发布时间】:2019-11-28 20:42:25
【问题描述】:

我有一个查询 MongoDB 数据库的应用程序,但目前只能查询文档中的单个字段:

export interface IKeyValue {
    [property : string] : any ;
}

export interface IFilter {
    [property : string] : IKeyValue;
}

const filter : IFilter = {
    "Name" : { $eq : "Bob" }
}

我想要做的是允许IFilter 允许多个属性:

const filter : IFilter = {
    "Name" : { $eq : "Bob" },
    "Age"  : { $gte : 21 }
}

我如何创建一个允许多个动态键的 Typescript 界面,而不恢复使用 objectany 作为 IFilter 的类型?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    我对您的需求的理解是:

    • 你有一些实体,比如说用户
    • 您想要创建可用于不同实体的通用过滤器类型
    • 通用过滤器类型应该对每个实体都是类型安全的

    首先让我们定义我们需要过滤的可能规则

    type Rule<T> = { $eq: T } | { $gte: T } // append any other rules you need
    

    我从您的示例中提取了两条规则 - $eq$gte 但您可以通过 | 添加您需要的其他规则。

    其次让我们定义泛型Filter 类型

    type Filter<Obj> = {
        [K in keyof Obj]: Rule<Obj[K]>
    }
    

    我们的类型说 - 我应该拥有给定对象的所有键,并且我应该为每个键定义一个规则,该规则适用于与此属性相同的类型。所以对于属性a: string,规则需要是或{$eq: string}{$gte: string}

    让我们看一个例子:

    // 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
    }
    

    类型Filter 是完全类型安全的,通过创建这种类型的实例,我们需要为这些键定义正确的键和正确的规则。

    作为补充,您可以有条件地说明哪些规则适用于哪些类型。假设$gte 仅适用于数字,但不适用于其他类型。你可以这样做:

    type Rule<T> = T extends number ? { $eq: T } | { $gte: T } : { $eq: T }
    

    以上定义将阻止将$gte 用于除数字以外的任何内容。

    【讨论】:

      【解决方案2】:

      我想要做的是让 IFilter 允许多个属性

      IFilter 是具有 string index signature 的类型,并且已经允许具有 string 名称类型和 IKeyValue 值类型的多个属性。只是 IDE/编译器无法帮助自动完成,因为它不知道由于 dynamic way the properties can be added 而内部是什么。

      例如,您的代码甚至对未知属性名称有效:

      const filterValue = filter["helloWorld"] // IKeyValue
      const keyValue = filter["hello"]["World"] // any
      

      我不确定,这里最好的解决方案是什么。如果IFilter 有一组修复(可能是可选的)属性名称,例如NameAge,则可能具有索引签名和已知属性的混合类型可以是created

      export interface IFilter {
        [property: string]: IKeyValue | undefined;
        Name?: IKeyValue;
        Age?: IKeyValue;
      }
      
      const filter : IFilter = {
        "Name": { $eq: "Bob" } // code assist for Name/Age properties
      }
      

      【讨论】:

        猜你喜欢
        • 2021-12-04
        • 1970-01-01
        • 2016-08-13
        • 1970-01-01
        • 2020-07-15
        • 2020-01-19
        • 1970-01-01
        • 2022-06-23
        • 2016-06-21
        相关资源
        最近更新 更多