how to (correctly) check if properties are optional
hesxenon

hesxenon @hesxenon

About: I just want to push the limits of myself while not descending into java-esque madness

Location:
vienna
Joined:
Nov 4, 2019

how to (correctly) check if properties are optional

Publish Date: Feb 4 '24
2 0

TL;DR

type IsKeyOptional<T extends Record<string | number | symbol, unknown>, Keys extends keyof T> = 
    {[Key in Keys]?: T[Key]} extends Pick<T, Keys> ? true : false;

type Foo = {
    foo?: string
    bar: string | undefined // this is not the same as foo!
}

type IsFooOptional = IsKeyOptional<Foo, "foo"> // true
type IsBarOptional = IsKeyOptional<Foo, "bar"> // false
Enter fullscreen mode Exit fullscreen mode

The problem

Recently I've run into a problem with using zod where zod deliberatly adds | undefined to the value of a key to then add the optional flag ? depending on whether or not the value includes undefined.

This check isn't accurate though as there is a fundamental difference between optional keys and nullable values, which is the exact reason why exactOptionalPropertyTypes exists. "IF you give me a banana, I expect it to be a banana, not a banana | undefined"

Correct checking

Think of objects as rows of [key, value] tuples for a second and the solution becomes clearer. In order to determine whether a key is optional we have to check whether the respective row is present, not whether the value includes undefined. And with that in mind we can just say

for a set of keys construct rows that are optional and check whether those rows are equal to the rows for the same keys from the type we want to check against

Or, more picturesque:

isOptional check control
false maybe the row exists the row DOES exist (even if its value can be undefined)
true maybe the row exists maybe the row exists

Comments 0 total

    Add comment