繁体   English   中英

TypeScript:键入递归类型

[英]TypeScript: Typing Recursive Type

我有一个查询,我根据用户输入生成客户端,看起来像这样。

const query = {
  "or": [
    {
      "field": "username",
      "operator": "in",
      "value": [
        "jdoe",
        "jsmith"
      ]
    },
    {
      "and": [
        {
          "field": "email",
          "operator": "matches",
          "value": "/^gmail.com/"
        },
        {
          "or": [
            {
              "field": "last_sign_in",
              "operator": "lt",
              "value": 1599619454323
            },
            {
              "field": "last_sign_in",
              "operator": "gt",
              "value": 1489613454395
            }
          ]
        }
      ]
    }
  ]
}

但是,为了将其迁移到简洁的 typescript 表示,我正在努力使其完全按照我想要的方式工作。

我有这些定义:


type Operator = 'eq' | 'in' | 'matches' | 'lt' | 'gt';
type Condition = 'and' | 'or' | 'not';

interface SimpleQuery {
  field: string;
  operator: Operator;
  value: any;
}

interface Query {
  condition: SimpleQuery[] // here I want `condition` to come from the type Condition
// I have tried these solutions involving [{ x of y }] https://github.com/microsoft/TypeScript/issues/24220
}

以下是我从 TS 编译器得到的错误:

A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.
A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
Cannot find name 'key'.
'Condition' only refers to a type, but is being used as a value here.

我试过这个

type Query = {
    [key in Condition]: SimpleQuery[];
}

使用这种方法 typescript 也希望我也添加所有缺失的条件。

我认为这将是描述您描述的对象的最准确类型::

type Operator = 'eq' | 'in' | 'matches' | 'lt' | 'gt';

type UnionKeys<T> = T extends T ? keyof T : never;
type Condition = UnionKeys<OperatorExpression>;

interface FieldCondition {
  field: string;
  operator: Operator;
  value: any;
}

type BinaryExpression<T extends PropertyKey> = {
    [P in T] : [FieldCondition | OperatorExpression, FieldCondition | OperatorExpression]
}
type UnaryExpression<T extends PropertyKey> = {
    [P in T] : [FieldCondition | OperatorExpression]
}

type OperatorExpression = BinaryExpression<"and"> | BinaryExpression<"or">  | UnaryExpression<"not"> 


const query: OperatorExpression = {
  "or": [
    {
      "field": "username",
      "operator": "in",
      "value": [
        "jdoe",
        "jsmith"
      ]
    },
    {
      "and": [
        {
          "field": "email",
          "operator": "matches",
          "value": "/^gmail.com/"
        },
        {
          "or": [
            {
              "field": "last_sign_in",
              "operator": "lt",
              "value": 1599619454323
            },
            {
              "field": "last_sign_in",
              "operator": "gt",
              "value": 1489613454395
            }
          ]
        }
      ]
    }
  ]
}

游乐场链接

此版本强制使用正确的逻辑运算符(使用元组类型)并基于运算符联合派生Condition联合。

这就是你要的查询界面吗? 它适用于您的query示例,但不确定它是否达到您想要的详细程度......

interface Query {
   [key:string]: (SimpleQuery | Query)[]; 
}

我认为您需要在这里进行递归( 操场):

type Operator = 'eq' | 'in' | 'matches' | 'lt' | 'gt';
type Condition = 'and' | 'or' | 'not';

interface SimpleQuery {
  field: string;
  operator: Operator;
  value: any;
}

type Query = {
  [key in Condition]: Array<SimpleQuery | Query>;
}

const query: Query = {
  "or": [
    {
      "field": "username",
      "operator": "in",
      "value": [
        "jdoe",
        "jsmith"
      ]
    },
    {
      "and": [
        {
          "field": "email",
          "operator": "matches",
          "value": "/^gmail.com/"
        },
        {
          "or": [
            {
              "field": "last_sign_in",
              "operator": "lt",
              "value": 1599619454323
            },
            {
              "field": "last_sign_in",
              "operator": "gt",
              "value": 1489613454395
            }
          ]
        }
      ]
    }
  ]
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM