Как использовать перегрузку функций для реализации функции двунаправленного отображения? - PullRequest
0 голосов
/ 28 декабря 2018

TL; DR

Попробуйте онлайн


У меня есть два типа объединения (оба строковых литерала) и жестко закодированный объект отображения, который отображает эти дватипы друг к другу.

type Digit = '1' | '2'
type Alpha = 'a' | 'b'
const map: Record<Digit, Alpha> & Record<Alpha, Digit> = {
    '1': 'a',
    '2': 'b',
    'a': '1',
    'b': '2'
}

Жестко закодированная карта хорошо работает, когда используется снова с одноэлементными значениями.

let digit: Digit = '1'
let alpha = map[digit] // alpha is inferred as Alpha
let digit2 = map[alpha] // digit2 is inferred as Digit

Возможно также обернуть ее функцией и затем отобразить массив.

let digitArr: Digit[] = ['1', '2']
let alphaArr = digitArr.map(d => map[d]) // inferred as Alpha[]

Но когда я хочу использовать только одну функцию с перегрузкой для достижения двунаправленного отображения, т.е.

digitArr.map(mapping) // returns Alpha[]
alphaArr.map(mapping) // returns Digit[]
// where digitArr and alphaArr is deterministically typed as Digit[] and Alpha[]

, система типов жалуется на это, и я не знаюкак сделать его счастливым.

Определение моей функции:

function overloadedMapping(digit: Digit): Alpha
function overloadedMapping(alpha: Alpha): Digit
function overloadedMapping(key: Digit | Alpha): Digit | Alpha {
    return map[key]
}

Эта функция также хорошо работает с одноэлементными значениями и завершается ошибкой в ​​одном виде массива.

let d = overloadedMapping('a') // d is of type Digit
let a = overloadedMapping('1') // a is of type Alpha
let arr = alphaArr.map(overloadedMapping) // arr is of type Digit[]. works? why?
let arr2 = digitArr.map(overloadedMapping) // type inference fails!! why?

Интересное наблюдение: когда переключается порядок объявления перегрузки, отображение массива, которое не выполняется, также чередуется.

Попробуйте его в режиме онлайн (аналогично первой ссылке)

1 Ответ

0 голосов
/ 28 декабря 2018

Если разрешение перегрузки не соответствует вашему обратному вызову с нужной подписью, вы можете сообщить TypeScript, что вы намерены сделать, явно указав параметр типа:

let arr2 = digitArr.map<Alpha>(overloadedMapping)

Теперь ваше преобразование будет обрабатываться как (value: Digit, index: number, array: Digit[]) => Alpha.

В этом случае отказ от стиля без точек поможет TypeScript также соответствовать перегрузке:

let arr2 = digitArr.map(digit => overloadedMapping(digit))
...