Skip to content

Conditional types do not work in generic functions #53455

Closed

Description

Bug Report

I've created a type that converts all undefined properties to optional. This types works well, however fails when used in generic functions:

type UndefinedKeys<T> = { [P in keyof T]: undefined extends T[P] ? P : never }[keyof T]
type OptionalUndefined<T> = Partial<Pick<T, UndefinedKeys<T>>> & Omit<T, UndefinedKeys<T>>

🔎 Search Terms

generic function

🕗 Version & Regression Information

This is the behavior in every version I tried ( 5.0.2 and 4.9.5 )

⏯ Playground Link

Playground link with relevant code

💻 Code

type UndefinedKeys<T> = { [P in keyof T]: undefined extends T[P] ? P : never }[keyof T]
type OptionalUndefined<T> = Partial<Pick<T, UndefinedKeys<T>>> & Omit<T, UndefinedKeys<T>>

type TSample<
  U extends Record<string, any> | undefined,
  D extends Record<string, any>
> = { undef: U, def: D }


function fn<
  U extends Record<string, any> | undefined,
  D extends Record<string, any>
>(params: OptionalUndefined<TSample<U, D>>) {
  {
    // ERROR: both properties do not exist on type 'OptionalUndefined<TSample<U, D>>'
    const { def, undef } = params
  }

  {
  // works as expected
  const { def, undef } = params as OptionalUndefined<
      TSample<
        Record<string, any> | undefined,
        Record<string, any>
      >
    > 
  }
}

🙁 Actual behavior

typescript cannot properly determine parameter type

🙂 Expected behavior

I expect typescript to use definition of U (extends Record<string, any> | undefined) and D (``) to be used to determine the type of parameters and params should have `{ undef?: Record<string, any> | undefined, def: Record<string, any> }` type?

Notice how, when I explicitly specify the type of params, it works properly.

Activity

  1. MartinJohns commented on Mar 23, 2023

    @MartinJohns
    Contributor

    Resolving of conditional types including unbound type arguments is deferred. This is a design limitation.

    TypeScript can't resolve your conditional type within the function because it doesn't know what types U and D are.

  2. fatcerberus commented on Mar 23, 2023

    @fatcerberus

    Conveniently, this issue makes a good case against #53452. Partial by itself currently works in generic contexts.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions