Skip to content

[5.1.0-dev.20230413] never function parameters will reject function call with no type parameters #53770

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

Closed
eps1lon opened this issue Apr 13, 2023 · 6 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@eps1lon
Copy link
Contributor

eps1lon commented Apr 13, 2023

Bug Report

πŸ”Ž Search Terms

never

πŸ•— Version & Regression Information

  • This changed between versions 5.0.4 and 5.1.0-dev.20230413

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

type BaseParams = {foo: string}
type OriginalParams<T> = T extends undefined ? [BaseParams?] : [BaseParams & T]

declare const optionalParam: (...params: OriginalParams<undefined>) => void
declare const noParam: (...params: OriginalParams<never>) => void

optionalParam()
optionalParam({foo: 'bar'})

// Argument of type '[]' is not assignable to parameter of type 'never'.(2345)
// Works in TS 5.0
noParam()

type StillBrokenParamsImpl<T> = T extends never ? [] : [true]
type NeverIn50AsWell = StillBrokenParamsImpl<never>
//   ^?
// should be [] to be useable as function parameter type
type Test = StillBrokenParamsImpl<undefined>
//   ^?
// expected: type Test = [true]

πŸ™ Actual behavior

never as a type for function parameters not usable to indicate "no arguments allowed"

πŸ™‚ Expected behavior

Some way to produce a type that results in no function arguments allowed. We used to do this with FunctionParams<never> but now it's no longer clear how to do it since AnyGenery<never> already produced never in TS 5.0

@Andarist
Copy link
Contributor

I'm a little bit confused by the phrasing of actual/expected results here. It reads to me that you want to create a function type that is not callable (no function arguments allowed) - and that's exactly the behavior that you get with (...args: never) => any in the current version of 5.1 (and what you show on the playground).

I feel like I'm misreading the intention here and I would appreciate if you could rephrase. Based on the observed change and the fact that you noticed this... I assume that you want to write a type in 5.1 with the 5.0 behavior~ and that your intention is to "remove" the parameter from the signature. You could do it like this:

type OriginalParams<T> = [T] extends [never]
  ? []
  : T extends undefined
  ? [BaseParams?]
  : [BaseParams & T];

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Apr 13, 2023

This code is doing exactly what you told it to do. 3.9 through 5.0 had a bug.

See #48840 (comment)

@eps1lon
Copy link
Contributor Author

eps1lon commented Apr 14, 2023

You could do it like this:

Yep that works. Not obvious to me why [T] extends [never] works but T extends never doesn't.

@Andarist
Copy link
Contributor

It's because T extends never is a distributive conditional type, each member of the union gets "processed" by the conditional type separately. Conceptually, a single-element union is still a union so we can kinda apply the same mental model for this. Taking this even further... never is an empty union so the conditional type isn't even processing it - we just get the "input" (never) back.

Wrapping T in the checkType of the conditional type makes it non-distributive and thus our input gets processed by this conditional type and we are actually able to make our desired check in it.

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Apr 14, 2023
@eps1lon
Copy link
Contributor Author

eps1lon commented Apr 14, 2023

I don't think this is useful to 99.99% of TypeScript users but y'all seem to be fine with this.

@eps1lon eps1lon closed this as not planned Won't fix, can't repro, duplicate, stale Apr 14, 2023
@fatcerberus
Copy link

Distributive behavior in conditional types is very useful and people use it all the time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

4 participants