Как правильно ввести функцию mapOptional в TypeScript? - PullRequest
0 голосов
/ 18 января 2019

У меня есть следующая функция, которая принимает необязательное значение и отображает его на другое значение, если оно не равно null или undefined.Мое текущее решение этой проблемы выглядит следующим образом:

type Return<I, R> = I extends null ? null
                  : I extends undefined ? undefined
                  : R;

/**
 * Maps an optional value to another optional by a callback.
 *
 * @param input - The input value to map.
 * @param callback - The callback to map the value.
 * @returns An optional mapped value.
 */
export function mapOptional<I, R>(input: I, callback: (value: NonNullable<I>) => R): Return<I, R> {
  if (input === null) {
    return null as Return<I, R>;
  }

  if (typeof input === 'undefined') {
    return undefined as Return<I, R>;
  }

  return callback(input!) as Return<I, R>;
}

Меня беспокоит две вещи:

  • Почему я должен привести возвращаемые значения к Return<I, R>?
  • Почему я должен использовать оператор взрыва !, чтобы ввод стал NonNullable?

Улучшение моего решения приветствовалось бы!

1 Ответ

0 голосов
/ 18 января 2019

В настоящее время условные типы имеют странную связь с типами возвращаемых функций, но в вашем случае вы можете сделать небольшую хитрость с перегрузкой, имеющей максимально широкий тип, а также обрабатывать крайние случаи вокруг известных null и undefined передается в функцию:

function mapOptional<I = any, R = unknown>(input: null, callback: (value: I) => R): null
function mapOptional<I = any, R = unknown>(input: undefined, callback: (value: I) => R): undefined
function mapOptional<I, R>(input: I, callback: (value: NonNullable<I>) => R)
    : I extends (undefined | null) ? I : R
function mapOptional<I, R>(input: I, callback: (value: I) => R) {
    if (input === null) {
        return null;
    }

    if (input === undefined) {
        return undefined;
    }


    return callback(input);
}

mapOptional(undefined, x => x.toFixed()) // type is undefined
mapOptional(null, x => x + 5) // type is null
mapOptional(56, x => x + 5).toFixed() // works

declare const optionalNumber: number | undefined

const r = mapOptional(optionalNumber, x => x + 5) // undefined | number
if (r) {
    console.log(r.toFixed())
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...