Skip to content

Add SetNullable type#1356

Open
derodero24 wants to merge 5 commits into
sindresorhus:mainfrom
derodero24:add/set-nullable
Open

Add SetNullable type#1356
derodero24 wants to merge 5 commits into
sindresorhus:mainfrom
derodero24:add/set-nullable

Conversation

@derodero24

Copy link
Copy Markdown
Contributor

Closes #697

Adds SetNullable<BaseType, Keys> — the inverse of SetNonNullable. Makes specified keys nullable by adding | null to their value types, while preserving readonly and optional modifiers.

If no keys are specified, all keys are made nullable (matching SetNonNullable's default behavior).

Implementation mirrors SetNonNullable using a homomorphic mapped type.

Comment thread test-d/set-nullable.ts
Comment thread test-d/set-nullable.ts

@som-sm som-sm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR LGTM, just one tiny question.

Comment thread test-d/set-nullable.ts
declare const variation4: SetNullable<{a: number | null; b: string}, 'a'>;
expectType<{a: number | null; b: string}>(variation4);

// Fail if type changes even if nullable is right.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYM by this? What's failing here?

@som-sm

som-sm commented Mar 15, 2026

Copy link
Copy Markdown
Collaborator

Also, maybe we should remove the keyof constraint from the second argument because, in the case of unions, it prevents updating keys that are not common across all members.

Currently, the JSDoc says:

If no keys are given, all keys will be made nullable.

But this is not true for unions:

type T = SetNullable<{a: number; b: number} | {a: string; c: string}>;
//=> {a: number | null; b: number} | {a: string | null; c: string}

And it's not that this behavior cannot be achieved. It can be achieved by using any as the second argument:

type T = SetNullable<{a: number; b: number} | {a: string; c: string}, any>;
//=> {a: number | null; b: number | null} | {a: string | null; c: string | null}

So even if we keep the keyof constraint, I guess a better default would be any. But I think the constraint should either be removed completely or at least replaced with KeysOfUnion. @sindresorhus WDYT?

@sindresorhus

Copy link
Copy Markdown
Owner

I think we should use KeysOfUnion.

We should probably make the same change to SetNonNullable too for consistency.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FR] SetNullable

3 participants