DEV Community

hesxenon
hesxenon

Posted on

how to (correctly) check if properties are optional

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

Top comments (0)