I have the following code:
type Success<T> = { success: true, value: T }
type Failure<E> = { success: false, error: E }
type Result<T, E = never> = Success<T> | Failure<E>
function succeed<T>(value: T): Result<T, never> {
return { success: true, value }
}
function fail<E>(error: E): Result<never, E> {
return { success: false, error }
}
function test(value: string): Result<string, string> {
if (value === undefined) {
return fail("empty");
} else {
return succeed(value);
}
}
I'm trying to optimize it so that when E
is never
, Result
is considered as a Success
result.
For this, I adapted the definition of Result
with the following conditional expression:
type Result<T, E = never> = [E] extends [never]
? Success<T>
: Success<T> | Failure<E>
Which raise a typescript error on the result
of the fail
method:
Type '{ success: false; error: E; }' is not assignable to type 'Result<never, E>'.
I am trying to correct this or find alternatives since a few days, but I don't understand why the conditional expression works for succeed
(when E is never
) and raise an error for the general case.
You encountered a case where TS doesn't support control flow for return conditional generic types. An easy solution would be use function overloads instead of a conditional type:
type Success<T> = { success: true, value: T }
type Failure<E> = { success: false, error: E }
function succeed<T>(value: T): Success<T> {
return { success: true, value }
}
function fail<E>(error: E): Failure<E> {
return { success: false, error }
}
type Simplify<T extends object> = {[K in keyof T]: T[K]} extends infer A ? A : never;
function test<T extends undefined>(value?: T): Simplify<Failure<'empty'>>;
function test<T extends string>(value: T): Simplify<Success<T>>;
function test(value?: string) {
if (value === undefined) {
return fail("empty");
} else {
return succeed(value);
}
}
const r = test(); // Failure
const r2 = test(undefined); // Failure
const r3 = test('data'); // Success