Conditional types can extract the payload type from a tagged response shape.

Response Payload Type

payload.ts
type Success<T> = { ok: true; value: T };
type Failure = { ok: false; error: string };
type Response<T> = Success<T> | Failure;

type PayloadOf<T> = T extends Success<infer U> ? U : string;

function describeResponse<T>(response: Response<T>): string {
    if (response.ok) {
        const payload: PayloadOf<Success<T>> = response.value;
        return `value:${payload}`;
    }
    const payload: PayloadOf<Failure> = response.error;
    return `error:${payload}`;
}

const okResponse: boolean = ;
const response: Response<number> = okResponse ? { ok: true, value: 7 } : { ok: false, error: "missing" };

console.log(describeResponse(response));
type Success<T> = { ok: true; value: T };
type Failure = { ok: false; error: string };
type Response<T> = Success<T> | Failure;

type PayloadOf<T> = T extends Success<infer U> ? U : string;

function describeResponse<T>(response: Response<T>): string {
    if (response.ok) {
        const payload: PayloadOf<Success<T>> = response.value;
        return `value:${payload}`;
    }
    const payload: PayloadOf<Failure> = response.error;
    return `error:${payload}`;
}

const okResponse: boolean = ;
const response: Response<number> = okResponse ? { ok: true, value: 7 } : { ok: false, error: "missing" };

console.log(describeResponse(response));
payload extraction Combining `extends` with `infer` can extract a nested type while a runtime branch handles success and failure.