Как сделать аргумент функции, который является универсальным объектом, потребляющим две функции с одним типом или void в Typescript

У меня следующая ситуация в машинописном тексте:

type Matcher<T, U> = {
  First: (arg: T) => U,
  Second: () => U
};

class Main<T> {    
  constructor(private value: T) {
  }

  match<U>(matcher: Matcher<T, U>): U {
    return this.value
      ? matcher.First(this.value)
      : matcher.Second();
  }
}

const main = new Main(10);

const res = main.match({ // there is a problem
  First: v => v + 10,
  Second: () => console.log()
});

Итак, у меня есть объект, который пользователь должен передать методу match экземпляра класса. Этот объект должен содержать две функции: First и Second. Эта функция возвращает значение одного типа (например, number) или одного типа + void (например, number + void), но ничего другого. Не может быть string + number типов.

Этот код не работает с ошибкой

The type argument for type parameter 'U' cannot be inferred from the usage. Consider specifying the type arguments explicitly. 
Type argument candidat 'void' is not a valid type argument because it is not a supertype of candidate 'number'.

Я понимаю, почему возникает эта ошибка (U - это единственный тип, но функции имеют два разных типа, и их нельзя объединять и т. Д.), Но как я могу решить эту проблему? Мне нужно:

  • строгая типизация, поэтому не должно быть типа any
  • разрешить использование только одного типа для обеих функций или void для одной или обеих. number и string как возвращаемые типы не допускаются.

Можно ли поступить с системой типов машинописного текста?


person Lodin    schedule 28.01.2017    source источник


Ответы (1)


Вы можете использовать типы объединения:

type Matcher<T, U> = {
    First: (arg: T) => U;
    Second: () => U | void
};

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

Но тогда вам понадобится метод match, чтобы также вернуть | void:

match<U>(matcher: Matcher<T, U>): U | void {
    return this.value
        ? matcher.First(this.value)
        : matcher.Second();
}

(код на игровой площадке)


Редактировать

Если я вас правильно понял, то это может помочь:

type Matcher<T, U> = {
    First: (arg: T) => U;
    Second: () => U;
};

type MatcherOne<T, U> = {
    First: (arg: T) => void;
    Second: () => U;
};

type MatcherTwo<T, U> = {
    First: (arg: T) => U;
    Second: () => void;
};

class Main<T> {
    constructor(private value: T) { }

    match<U>(matcher: Matcher<T, U>): U;
    match<U>(matcher: MatcherOne<T, U>): U | void;
    match<U>(matcher: MatcherTwo<T, U>): U | void;
    match<U>(matcher: Matcher<T, U> | MatcherOne<T, U> | MatcherTwo<T, U>): U | void {
        return this.value
            ? matcher.First(this.value)
            : matcher.Second();
    }
}

( код на игровой площадке )

person Nitzan Tomer    schedule 28.01.2017
comment
Он по-прежнему жалуется, что аргумент типа не может быть выведен из использования. - person Lodin; 28.01.2017
comment
Добавлена ​​ссылка на версию для игровой площадки, которая соответствует требованиям. - person Nitzan Tomer; 28.01.2017
comment
Может быть какое-то недоразумение. Я хотел, чтобы обе функции в сопоставлении могли быть недействительными или одного типа. Поэтому я просто добавил void в качестве второго типа к первой и второй функциям, и это не удалось скомпилировать. - person Lodin; 28.01.2017
comment
Так что теперь все в порядке? Или у вас все еще есть проблема? - person Nitzan Tomer; 28.01.2017
comment
Мне нужен объект, который позволяет пользователю отправлять объект { First: void, Second: number }, { First: string, Second: void } или { First: array, Second: array }, поэтому просто включить void в функции Second или First недостаточно. - person Lodin; 28.01.2017