简体   繁体   中英

Mapped types: Make property required based on whether array of same object contains string literal

Is it possible to make an object property dependent on whether an array of the same object contains a string literal?

type Operator = "A" |  "B"
type SomeStruct = {
    operators: Operator[];
    someProp: string; // this should be required if operators include "A", optional if not
}

// desired result
const structWithA: SomeStruct = {
  operators: ["A", "B"],
  someProp: "" // correct, since operators contains "A", someProp is required
};

const structWithB: SomeStruct = {
  operators: ["B"],
  // currently errors, but desired outcome is that it should not error, since operators does not contain "A"
};

declare const structs: SomeStruct[];

structs.map(struct => {
  if(struct.operators.includes("A")) {
    // someProp is safely accessible
  }

  // since .includes has a narrow type signature, maybe another way to safely access someProp is needed 
})

By using an identity function to create your structs (and a predicate to discriminate its type), you can accomplish this:

TS Playground

type A = 'A';
type B = 'B';
type Operator = A | B;

type SomeStruct<T extends readonly Operator[]> = { operators: T; } & (
  T extends readonly A[] ?
    Record<'someProp', string>
    : unknown
);

function craeteStruct <O extends readonly Operator[], T extends SomeStruct<O>>(struct: T): T {
  return struct;
}

const structWithA = craeteStruct({
  operators: ["A", "B"],
  someProp: "",
});

const structWithB = craeteStruct({
  operators: ["B"],
});

declare const structs: (SomeStruct<Operator[]>)[];

function includesA (struct: SomeStruct<Operator[]>): struct is SomeStruct<A[]> {
  return struct.operators.includes('A');
}

structs.map(struct => {
  if(includesA(struct)) {
    struct.someProp; // string
  }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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