Это все неправильно:
map: <S>(fn: (x: T) => S) => T extends null | undefined ? Maybe<S> : Maybe<T>;
Я думаю, вы имели в виду
map: <S>(fn: (x: T) => S) => T extends null | undefined ? Maybe<T> : Maybe<S>;
, потому что весь смысл, возможно, заключается в том, чтобы остановить вычисления, если T расширяет null | неопределенный. в любом случае, что вы делаете, это просите машинописный текст вычислить, является ли экземпляр «возможно» ничем перед выполнением программы. Смысл использования «может быть» не в этом, и это не дает никакой пользы. Я бы рекомендовал написать тип Maybe, который выражает наличие типа A или наличие нулевого типа отдельно от вашего типа для map
Пример реализации:
type Some<A> = { _tag: 'some', val: A };
type None = { _tag: 'none' };
// this is the lazy way to express T extends null | undefined ? Maybe<T> : Maybe<S>;
// we dont care about computing it while writing a program, only that the program handles
// the none type
export type Maybe<A> = Some<A> | None;
const Some = <A>(a): Maybe<A> => ({ _tag: 'some', val: a });
const None = <A = unknown>(): Maybe<A> => ({ _tag: 'none' });
const isNone = <A = unknown>(fa: Maybe<A>) => fa._tag === 'none';
// (f) => (fa) => (fb)
const map = <A, B>(f: (a: A) => B, fa: Maybe<A>): Maybe<B> =>
fa._tag === 'none' ? None() : Some(f(fa.val));
const chain = <A, B>(f: (a: A) => Maybe<B>, fa: Maybe<A>): Maybe<B> =>
fa._tag === 'none' ? None() : f(fa.val);
export const Maybe = {
Some,
None,
isNone,
map,
chain,
};