简体   繁体   中英

Typescript: conditionally mark an object property as optional?

Eg:

type Foo = {
    'a': string,
    'b': undefined,
};

type Bar<T extends keyof Foo> = {
    foo: Foo[T],
};

const bar1: Bar<'a'> = { foo: 'a' }; // ok
const bar2: Bar<'b'> = { foo: undefined }; // ok
const bar3: Bar<'b'> = {}; // Property 'foo' is missing in type '{}' but required in type 'Bar<"b">'.

TS Playground: https://www.typescriptlang.org/play?#code/C4TwDgpgBAYg9nKBeKBvAUFLUDkBDHALigGdgAnASwDsBzAGk2xwCMioBXagEwgDMaEbowC+AbnTpQkKACE85ADwAVKBAAewCDxJQA1hBBw+sBAD5kaJlj4Ji8OAG1lAXVET0AYzjUyUFgoAjMTySvg4FiioULZwxOFQ4l4+fgHkAEwhCoqsEZbRscRcvALUQokS3r7A-goAzFlhbJFo4kA

In this example, I want the foo property to be optional if its value is undefined . In other words, I want { foo: undefined } and {} to be interchangeable.

In my actual code, I have API handlers that conditionally return different fields. If a field is not needed, I want to omit it instead of having to define it as undefined .

One way to fix this is:

type Bar<T extends keyof Foo> = Foo[T] extends undefined
  ? { foo?: undefined }
  : { foo: Foo[T] };

However, if a lot of fields are optional, then the conditional can become very long. Is there a better way?

type Foo = {
    'a': string,
    'b': undefined,
}

type Bar<T extends keyof Foo> = {
    propOne: Foo[T],
    propTwo: Foo[T]
};

type UndefinedBarKeys<T extends keyof Foo> = {
  [K in keyof Bar<T>]: Bar<T>[K] extends undefined ? K : never 
}[keyof Bar<T>];

type BetterBar<T extends keyof Foo> =
    Foo[T] extends undefined
    ? { [K in keyof Pick<Bar<T>, UndefinedBarKeys<T>>]?: Foo[T] }
    : Bar<T>;

const bar1: BetterBar<'a'> = { propOne: 'asdf', propTwo: 'qwerty'};
const bar2: BetterBar<'b'> = { propOne: undefined, propTwo: undefined };
const bar3: BetterBar<'b'> = {};

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