Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: [NormalizeOptional] Mark all keys which accept undefined as optional #373

Open
IlyaSemenov opened this issue Jul 11, 2023 · 4 comments
Labels
enhancement New feature or request

Comments

@IlyaSemenov
Copy link
Contributor

What

I propose type NormalizeOptional<Type>:

  • to mark all keys that accept undefined as optional

With implementation similar to:

type NormalizeOptional<T> = MarkOptional<T, PossiblyUndefinedKeys<T>>

type PossiblyUndefinedKeys<Type> = {
  [Key in keyof Type]: undefined extends Type[Key] ? Key : never
}[keyof Type]

Examples

Sometimes, a generic will construct a type which keys allow undefined but are not marked as optional. The proposed NormalizeOptional<Type> will mark such keys as optional.

type DefineParams<Keys extends string, Defaults> = {
  [K in Keys]: K extends keyof Defaults ? number | undefined : number
}

const defaults = { foo: 1 }

type Params = DefineParams<"foo" | "bar", typeof defaults>

function f1(params: Params) {}

// Error: Property 'foo' is missing in type '{ bar: number; }' but required in type 'Params'
f1({ bar: 1 })

// OK, but has redundant undefined
f1({ foo: undefined, bar: 1 })

function f2(params: NormalizeOptional<Params>) {}

// OK
f2({ bar: 1 })

Additional Info

No response

@IlyaSemenov IlyaSemenov added the enhancement New feature or request label Jul 11, 2023
@Beraliv
Copy link
Collaborator

Beraliv commented Jul 18, 2023

@IlyaSemenov hey!

Thank you for the enhancement!

I will need to have a look at this to understand if there are any quirks with assignability when we normalise a type (e.g. union of objects)

I will let you know when I do this

@IlyaSemenov
Copy link
Contributor Author

By the way, I just happened to face a reverse problem (vueuse/vueuse#3546): I needed to unmark keys accepting undefined as being optional:

type A = { foo: string; bar?: string }
type FixedA = { foo: string; bar: string | undefined } // bar always exists in keys (even if the value is undefined)

@Beraliv
Copy link
Collaborator

Beraliv commented Nov 20, 2023

By the way, I just happened to face a reverse problem (vueuse/vueuse#3546): I needed to unmark keys accepting undefined as being optional:

type A = { foo: string; bar?: string }
type FixedA = { foo: string; bar: string | undefined } // bar always exists in keys (even if the value is undefined)

I see.

One thing to add here is that composition of MarkOptional and UnmarkOptional isn't going to be homomorphic in general.

This would be complicated to find out about so developers need to be very careful with such feature request. It may bring a lot of confusion so picking right name would be very challenging here

@Beraliv
Copy link
Collaborator

Beraliv commented May 1, 2024

Hey @IlyaSemenov! As some time passed, do you still use this utility type, how does it behave in the codebase, did you find out about the edge cases and best practices?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants