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
is that the
Parameters<T>utility type is defined aswhere its type parameter is constrained to the function type expression
(...args: any) => any,while you have only checked the
ErrorsType[T]type argument against theFunctioninterface. And while(...args: any) => anyis assignable toFunction, the reverse is not true: just because something is aFunctionthe compiler does not know that it is a(...args: any) => any. TheFunctiontype 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
Functionto(...args: any) => any:Or the equivalent inlined version:
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.
Playground link to code