Skip to content

Parameters typed as unknown even when the function type has the correct types #57654

Open

Description

@Didas-git

🔎 Search Terms

mapped types, function types

🕗 Version & Regression Information

  • This is the behavior that starts in version 4.9, and I reviewed the FAQ for entries about function types
    All the versions prior to 4.9 have both scenarios with the params typed to unknown

⏯ Playground Link

Playground Link

💻 Code

No response

🙁 Actual behavior

The function with no default shows the proper function type but the parameters are typed as unknown

🙂 Expected behavior

The parameters should have the types of the function params

Additional information about the issue

There is also a smaller reproduction that was made by mkantor on discord.

Activity

  1. Andarist commented on Mar 5, 2024

    @Andarist
    Contributor

    This is the behavior that starts in version 4.9, and I reviewed the FAQ for entries about function types
    All the versions prior to 4.9 have both scenarios with the params typed to unknown

    I'm pretty sure that the observed behavior change is related to #50994

  2. RyanCavanaugh commented on Mar 6, 2024

    @RyanCavanaugh
    Member

    (Speaking only to the reduced repro; the longer one is way too long)

    These functions as written are sort of bad beyond salvaging through inference. There aren't any "good" inference sites for T so end up having observable differences between falling back to the default vs the constraint.

    I guess I'd argue that unknown is the correct behavior here, since a body of these functions could call it with non-"wtf" values:

    function noDefaultTypeParameter<T extends Callback>(f: Listener<T>) {
      f(423);
    }

    But there's really no reason to write Listener this way; it's already distributive and null and undefined will not match the infer. Writing it this way:

    type Listener<T> =
      T extends (arg: infer U) => unknown
        ? (arg: U) => unknown
        : never

    causes both function's behavior to align, and correctly makes it an error to invoke f(423) in the bodies.

    Barring a more realistic repro I don't have a well-justified behavior change.

  3. Didas-git commented on Mar 6, 2024

    @Didas-git
    Author

    I have reduced the big example as much as i could to reflect what im really using it for, i also added some more examples (one of the examples just left me speachless because i really dont understand whats going on)
    Here is the link

  4. RyanCavanaugh commented on Mar 6, 2024

    @RyanCavanaugh
    Member

    Can I get more concrete/descriptive "what I expected to happen"s than "Uhm??". I know it's obvious to you but it's a lot of work for me to reconstruct your mental state

  5. Didas-git commented on Mar 6, 2024

    @Didas-git
    Author

    Well, typescript reports the type of the function ready so i expected the arguments to be typed as well, but what really left me speachless and with no more ideas was the last one where the function is typed to (arg: string) => unknown yet the argument is typed as something completely different, not even unknown

  6. Forlini91 commented on Mar 7, 2024

    @Forlini91

    It seems a problem with optional properties of objects.
    You're iterating all keys in Transformers [K in keyof T], and Transformers has the optional property "ready".
    When you do T[K], it find that optional property and read it as <type of that property> | undefined, and this makes the conditional type T[K] extends { handler: ... fail, because it doesn't match the "undefined" part of the type.

    Adding & {} (as you did) entirely remove the "undefined" from the type, and this explains why it works.
    Changing the conditional type to T[K] extends undefined | { handler: ... also works, because we're including the possibility for undefined.

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

    Needs More InfoThe issue still hasn't been fully clarified

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions