Typescript перегружает необязательный параметр в двух функциях

У меня есть функция распознавателя, которая может иметь необязательный второй параметр с именем otherParams. Я хотел бы, чтобы Typescript проверял, вызывается ли функция, возвращаемая из createResourceThunk, с параметром otherParams, если он определен в функции разрешения. Как я могу это сделать? Minimal reproducable example here

export function createResourceThunk<T, Params, A, OtherParams extends A | never>(
  actions: ResourceActions<T>,
  resolver: (params: Params, otherParams: OtherParams) => Promise<T>
) {
  return function(params: Params, callbacks: Callbacks<T>, otherParams: OtherParams) {
    return async (dispatch: Dispatch) => {
      dispatch(actions.startAction());
      try {
        const data = await (otherParams ? resolver(params, otherParams) : resolver(params));
        ...
      } catch (error) {
        ...
      }
    };
  };
}

В настоящее время он всегда ожидает третий параметр в вызове возвращаемой функции.


person velop    schedule 03.02.2021    source источник
comment
Рассмотрите возможность изменения кода здесь, чтобы он представлял собой минимально воспроизводимый пример, подходящий для добавления в автономную среду IDE, например Площадка TypeScript, где другие могут продемонстрировать вашу проблему (и только вашу) для себя. Гораздо легче помочь, если я смогу начать с вашей проблемы, а не создавать ее заново.   -  person jcalz    schedule 03.02.2021
comment
Что ты делаешь с A | never? Это немедленно уменьшается до A несмотря ни на что. Кроме того, в вашем минимально воспроизводимом примере я бы предложил показать несколько вариантов использования вызова createResourceThunk() и вызова того, что он возвращает , с параметрами resolver, которые принимают/не принимают второй параметр, чтобы люди могли продемонстрировать, что должно происходить. В противном случае вы получите ответ, просто сделайте otherParams необязательным везде с ?.   -  person jcalz    schedule 03.02.2021
comment
Подходит ли это для ваших случаев использования? Если нет, уточните, желательно с минимально воспроизводимым примером, который показывает, что вам нужно. (Хм, я упоминал, что вы должны предоставить минимально воспроизводимый пример? Здесь есть эхо? ????)   -  person jcalz    schedule 03.02.2021
comment
@jcalz Ха-ха, вы абсолютно правы с эхом, а также с тем, что я должен был создать минимальную ре. Добавлю к вопросу. Спасибо, что указали на игровую площадку машинописного текста для этого   -  person velop    schedule 05.02.2021
comment
Кстати. тип AddBetween взят из stackoverflow.com/questions/53985074/   -  person velop    schedule 05.02.2021
comment
Пожалуйста, отредактируйте код в тексте вопроса, чтобы отразить то, что происходит в вашем минимально воспроизводимом примере; Я сейчас пишу ответ.   -  person jcalz    schedule 05.02.2021


Ответы (1)


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

export function createResourceThunk<T, P, O extends [] | [otherParams: any]>(
  actions: ResourceActions<T>,
  resolver: (params: P, ...args: O) => Promise<T>
) {

  return function (params: P, callbacks: Callbacks<T>, ...otherParamsArr: O) {
    const [otherParams] = otherParamsArr; // if you care
    return async (dispatch: Dispatch) => {
      dispatch(actions.startAction());
      try {
        const data = await resolver(params, ...otherParamsArr);
        dispatch(actions.successAction({ data }));
        callbacks && callbacks.onSuccess && callbacks.onSuccess({ data });
      } catch (error) {
        dispatch(actions.errorAction({ error }));
        callbacks && callbacks.onError && callbacks.onError({ error });
      }
    };
  }
}

Важным моментом здесь является то, что необязательный второй параметр представлен как остаточный аргумент, тип которого является union типы остальных кортежей. Параметр типа O представляет собой список параметров после аргумента params. Он ограничен либо нулевыми элементами ([]), либо одним элементом ([otherParams: any]). Таким образом, везде, где вы хотели сказать otherParams, вы должны использовать остаточный параметр, такой как ...otherParamsArr.

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

// with OptionalParam
const func1 = createResourceThunk('any', (a: { a: number }, b: string) => Promise.resolve('any'))
func1({ a: 1 }, { successAction: () => { } }, 'somestring') // okay
func1({ a: 1 }, { successAction: () => { } }); // error

// without OptionalParam
const func2 = createResourceThunk('any', (a: { a: number }) => Promise.resolve('any'))
func2({ a: 1 }, { successAction: () => { } }) // okay
func2({ a: 1 }, { successAction: () => { } }, 'somestring') // error

Ссылка на код

person jcalz    schedule 05.02.2021
comment
Спасибо за вашу помощь. Это делает замечательную работу - person velop; 16.02.2021