When I use Typescript Conditional Statement it doesn't remove the values. For example, if the type of "ErrorsType
" is string
| null
, and I use ErrorsType extends string ? InHereTheValueOf'ErrorsType'IsStill'String'|'null'InsteadOf'String' : InHereTheValueOf'ErrorsType'IsStill'String'|'null'InsteadOf'null'
Here is my code:
export const BotErrors = {
test: (reason: string) => `This error bc of ${reason}`,
ValueTooLow: 'You can not reduce value below 0',
};
type ErrorsType = typeof BotErrors;
export default class SomeError<T extends keyof ErrorsType> extends Error {
constructor(code: T, ...args: ErrorsType[T] extends Function ? Parameters<ErrorsType[T]> : []) {
let msg: string | Function = BotErrors[code];
if (typeof msg === 'function') msg = msg(...args) as string;
super(msg);
}
}
At ErrorsType[T]
got error: Type 'Function & { test: (reason: string) => string; ValueTooLow: string; }[T]' does not satisfy the constraint '(...args: any) => any'.
Because of the BotErrors
have both function and string as it's value.
After I add // @ts-nocheck
everything is fine, even with type definition. But I'm try wondering if there is any way to not ignore errors?
The problem with
ErrorsType[T] extends Function ? Parameters<ErrorsType[T]> : []
is that the Parameters<T>
utility type is defined as
type Parameters<T extends (...args: any) => any> =
T extends (...args: infer P) => any ? P : never;
where its type parameter is constrained to the function type expression (...args: any) => any
,
while you have only checked the ErrorsType[T]
type argument against the Function
interface. And while (...args: any) => any
is assignable to Function
, the reverse is not true: just because something is a Function
the compiler does not know that it is a (...args: any) => any
. The Function
type is best avoided in general, since it represents untyped function calls.
Anyway it's easy enough to fix this; just change the conditional type check from Function
to (...args: any) => any
:
ErrorsType[T] extends (...args: any) => any ? Parameters<ErrorsType[T]> : []
Or the equivalent inlined version:
ErrorsType[T] extends (...args: infer P) => any ? P : []
This makes the error you mentioned go away. Note that once this is resolved your example code has other errors, but those are out of scope for the question as asked.