Búsqueda de sitios web

TypeScript no detecta la sobrecarga de función correcta


Dada la siguiente implementación de función:

function fmap<T, U>(value: T, f: (x: T) => U): U;
function fmap<T, U>(value: T | undefined, f: (x: T) => U): U | undefined;
function fmap<T, U>(value: T | null, f: (x: T) => U): U | null;
function fmap<T, U>(value: T | null | undefined, f: (x: T) => U): U | null | undefined {
    return value === undefined ? undefined : value === null ? null : f(value);
}

Obtengo los tipos correctos en los siguientes casos:

const test1 = (v: string) => fmap(v, x => x); // ✅ expected: string
const test2 = (v: string | null) => fmap(v, x => x); // ✅ expected: string | null
const test3 = (v: string | undefined) => fmap(v, x => x); // ✅ expected: string | undefined
const test4 = (v: string | null | undefined) => fmap(v, x => x); // ✅ expected: string | null | undefined
const test5 = (v: string) => fmap(v, x => 1); // ✅ expected: number

Pero no en estos casos:

// ❌ expected: number | null (actual: number)
const test6 = (v: string | null) => fmap(v, x => 1);

// ❌ expected: number | undefined (actual: number)
const test7 = (v: string | undefined) => fmap(v, x => 1);

// ❌ expected: number | null | undefined (actual: number)
const test8 = (v: string | null | undefined) => fmap(v, x => 1);

Ver patio de recreo

Respuesta #1

Necesitarás extraer los tipos anulables del tipo genérico T

type ExtractedNullable<T> = Extract<T, null | undefined>

function fmap<T, U>(value: T, f: (x: T) => U): U | ExtractedNullable<T> {
    return value === undefined ? undefined as ExtractedNullable<T> : value === null ? null as ExtractedNullable<T> : f(value);
}

const test1 = (v: string) => fmap(v, x => x); // ✅ expected: string
const test2 = (v: string | null) => fmap(v, x => x); // ✅ expected: string | null
const test3 = (v: string | undefined) => fmap(v, x => x); // ✅ expected: string | undefined
const test4 = (v: string | null | undefined) => fmap(v, x => x); // ✅ expected: string | null | undefined
const test5 = (v: string) => fmap(v, x => 1); // ✅ expected: number

const test6 = (v: string | null) => fmap(v, x => 1); // number | null

const test7 = (v: string | undefined) => fmap(v, x => 1); // number | undefined

const test8 = (v: string | null | undefined) => fmap(v, x => 1); // number | null | undefined 

Artículos relacionados