microsoft/TypeScript

`ReturnType` and `InstanceType` don't work for functions/constructors with `never` in their parameters

Opened this issue ยท 3 comments

๐Ÿ”Ž Search Terms

ReturnType InstanceType any never

๐Ÿ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about ReturnType and InstanceType.

โฏ Playground Link

https://www.typescriptlang.org/play#code/C4TwDgpgBA+gjFAvFAShYBXATgOwCrgQA8AFAHQUCGWA5gM4BcUOEAbhFgJRIB8UA5ADMA9sP48AUAHopUOQD0A-BImhIsAExIoASRx1glHAGMIBSERYB3KOSq1GzNh26I+Q0eOmyFioA

๐Ÿ’ป Code

type _1 = ReturnType<(...args: never) => 'foo'>
//   ^? type _1 = any

type _2 = InstanceType<new (...args: never) => 'foo'>
//   ^? type _2 = any

๐Ÿ™ Actual behavior

ReturnType and InstanceType always evaluate to any when given a function/constructor whose parameters are ...args: never (or ...args: never[], a: never, b: string, etc).

๐Ÿ™‚ Expected behavior

ReturnType and InstanceType should return the actual return/instance type.

Additional information about the issue

Changing the parameter constraint in the conditions of these types from any to never seems to fix the issue:

type ReturnType<T extends (...args: any) => any> = T extends (...args: never) => infer R ? R : any

type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: never) => infer R ? R : any

I don't think this will cause any regressions, and did some spot-checking to validate that, but haven't run the entire test suite or anything like that yet.

If someone wants to put up a PR for the suggested lib file change, we can run the battery of test suites against it and see if any breaks turn up in the wild.

Given that (...args: Array<never>) => unknown does not work with the built-in ReturnType<F> utility type, I have to assume there is a different intended way of representing the type of "all possible functions." How would one do so without using any, which is unsafe?

I assumed the same as OP, based on the rules for function subtyping. Flow also uses (...$ReadOnlyArray<empty>) => mixed, which is their equivalent (modulo the ReadonlyArray).

However, I have been unable to find anything through experimentation, and the Functions documentation doesn't mention this at all.

@sliminality

I have to assume there is a different intended way of representing the type of "all possible functions."

I think this is just a bug/oversight, not signalling that (...args: never) => unknown1 is intended to be avoided. The pull request which would close this issue is in limbo, but never-typed parameters "should" be acceptable.

If you want a pragmatic answer to "what do I do in the meantime?": it depends, but you could use any in parameters in situations where there's no callable value anyway (in that case it's safe), or use never and avoid applying the built-in ReturnType & InstanceType utility types in these cases. I typically do the latter and just inline an infer when I need to extract a return type.

Footnotes

  1. By the way, (...args: never) => unknown is a safer top function type than (...args: Array<never>) => unknown. โ†ฉ