TypeScript: общая функция switchExpression для различающихся союзов - PullRequest
0 голосов
/ 22 октября 2018

Я пытаюсь создать функцию выражения переключателя общего назначения, которая может принимать любой дискриминируемый тип объединения (для простоты, используя свойство типа в качестве дискриминатора) и сопоставлять его значения дискриминатора с функциями обратного вызова и возвращать результат соответствующегообратный вызов.

например

type One = {
  type: 'one',
  numeric: number
};

type Two = {
  type: 'two',
  text: string
};

type Union = One | Two;

const union: Union = ... // some appropriate assignment

// The function switchExp should be aware of what the map should 
// look like based on the type of its first arg. The argument
// passed to each callback should be properly discriminated based
// on the key in the map.
let result: number | string = switchExp(union, {
  one: u => u.numeric, // compiler should know that u is of type One
  two: u => u.text // compiler should know that u is of type Two
});

1 Ответ

0 голосов
/ 22 октября 2018

Мы можем использовать сопоставленный тип и условный тип ReturnValue, чтобы получить желаемый эффект.Однако есть некоторая загвоздка в том, как мы можем вывести типы для параметров функции.Если мы попытаемся сделать это за один вызов функции, параметры будут набраны как any.

Так, например, это не будет работать должным образом:

function switchExp2<T extends { type: string }, R extends { [P in (T["type"]]: (v: Extract<T, { type: P }>) => any }>(u: T, o: R): ReturnType<R[keyof R]> {
    return null as any;

}

let result2 = switchExp2(union, {
    one: u => u.numeric, // u is implictly tyed as any
    two: u => u.text // u is implictly tyed as any
});

Компилятор пытается вывести T из всех возможных сайтов и просто сдается вместо того, чтобы прийти к выводу.Простое решение состоит в том, чтобы сначала исправить T, а затем выполнить второй вызов для отображаемого объекта:

function switchExp<T extends { type: string }>(u: T) {
    return function <R extends { [P in T["type"]]: (v: Extract<T, { type: P }>) => any }>(o: R): ReturnType<R[keyof R]> {
        return null as any; // replace with reasonable implementation 
    }
}

let result: number | string = switchExp(union)({
    one: u => u.numeric, //u is of type One
    two: u => u.text //  u is of type Two
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...