typescript - Cum pot determina tipul altei proprietăți a aceluiași obiect în funcție de valoarea proprietății obiectului?


Am tipurile după cum urmează:

type Operators =
    | "eq"
    | "ne"
    | "lt"
    | "gt"
    | "lte"
    | "gte"
    | "in"
    | "nin"
    | "contains"
    | "ncontains"
    | "containss"
    | "ncontainss"
    | "between"
    | "nbetween"
    | "null"
    | "nnull"
    | "or"

type Filter = {
    field: string;
    operator: Operators;
    value: any
};

export type Filters = Filter[];

Ceea ce încerc să fac este să definesc tipul Filter prin tipul Operators.

Dacă utilizatorul specifică Operators ca "or", atunci proprietatea field nu este necesară și proprietatea value este de tip Filters. După cum urmează:

export type Filter = {
    field: string | undefined;
    operator: Operators;
    value: Filters;
};

Dacă utilizatorul specifică Operators diferiți de "or", atunci proprietatea field este obligatorie și proprietatea value poate fi de orice tip. După cum urmează:

export type Filter = {
    field: string;
    operator: Operators;
    value: any
};

Cum pot determina tipul altei proprietăți a aceluiași obiect în funcție de valoarea proprietății obiectului?

Răspuns #1

Poți defini tipul Filters ca un array de tip Union pentru a comuta între condițiile tale de tip.

/** Separating the operators type into two; not fully needed but easier to understand imo **/

type LogicalOperators = 
    | "eq"
    | "ne"
    | "lt"
    | "gt"
    | "lte"
    | "gte"
    | "in"
    | "nin"
    | "contains"
    | "ncontains"
    | "containss"
    | "ncontainss"
    | "between"
    | "nbetween"
    | "null"
    | "nnull";


type ConditionalOperators = "or" | "and";

/** Intersect these two type, so you can reference it easier later. **/
type Operators = LogicalOperators & ConditionalOperators;

/** Checking the value by the operator and field **/
type LogicalFilter = {
    field: string;
    operator: LogicalOperators;
    value: any
};

/** Combining filters with `or` or `and` **/
type ConditionalFilter = {
    operator: ConditionalOperators;
    value: Filters;
}

/** Define the Filters type as a union **/
type Filters = (LogicalFilter | ConditionalFilter)[];

Deci, când poți folosi tipul Filters astfel;

const isApple: Filters = [{ field: "fruitName", operator: "eq", value: "Apple" }];

const isAppleOrPear: Filters = [{ operator: "or", value: [{ field: "fruitName", operator: "eq", value: "Apple" }, { field: "fruitName", operator: "eq", value: "Pear" }] }];

Răspunsul #2

Dacă folosești Enum-uri, poți face câmpul obligatoriu dacă Operatorul este egal cu Sau.

enum Operators {
  Eq = "eq",
  Ne = "ne",
  Or = "or"
}

type Filter = {
    field: string;
    operator: Operators.Or;
    value: any
} | type Filter = {
    field: string;
    operator: Operators.Or;
    value: any
} | {
    field?: string;
    operator: Exclude<Operators, Operators.Or>
    value: any
};

// field is required
const filterOr: Filter = {
    field: 'field', 
    value: 'string',
    operator: Operators.Or
}

// field is not required
const filterEq: Filter = {
    value: 'string',
    operator: Operators.Eq
}

const filterEe: Filter = {
    value: 'string',
    operator: Operators.Ne
}