У типа функции должен быть условный необязательный аргумент - PullRequest
0 голосов
/ 11 января 2020

У меня есть два обобщенных c типа, которые можно использовать с моими редукционными действиями и создателями действий. Я пытаюсь сделать условный тип функции общего назначения c необязательным аргументом, основанным на переданном аргументе. Есть ли более элегантный способ написать GenericActionCreator ниже?

import { AnyAction } from 'redux';

interface GenericAction<TType extends string, TPayload = undefined> extends AnyAction {
  type: TType;
  payload: TPayload;
}

// This function checks if the payload property on the passed in TAction can be undefined.
// If it can be undefined, then the payload argument becomes optional, otherwise it is
// required. 
type GenericActionCreator<
  TAction extends GenericAction<string, TAction['payload']>
> = Extract<TAction['payload'], undefined> extends never
  ? (payload: TAction['payload']) => TAction
  : (payload?: TAction['payload']) => TAction;


type RequiredPayloadAction = GenericAction<string, boolean>;
type RequiredPayloadActionCreator = GenericActionCreator<RequiredPayloadAction>;
// output: type RequiredPayloadActionCreator = (payload: boolean) => RequiredPayloadAction

type OptionalPayloadAction = GenericAction<string, boolean | undefined>;
type OptionalPayloadActionCreator = GenericActionCreator<OptionalPayloadAction>;
// output: type OptionalPayloadActionCreator = (payload?: boolean | undefined) => OptionalPayloadAction

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

1 Ответ

1 голос
/ 12 января 2020

Если ваш существующий GenericActionCreator<T> подходит для ваших сценариев использования, он мне подходит.

Есть, конечно, разные способы получить поведение, о котором вы говорите ... но я не понимаю Не знаю, что кто-то из них более «элегантный» (или, по крайней мере, это вопрос мнения). Вот версия, которая дает те же типы вывода, что и у вас (обратите внимание, что имена параметров функции не считаются частью типа ... поэтому (x: string)=>void и (y: string)=>void - это один и тот же тип), но выражает это по-разному:

type GenericActionCreator<T extends GenericAction<string, unknown>, P = T["payload"]> =
  (...p: undefined extends P ? [P?] : [P]) => T

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

  • У меня есть заменил TAction на T. Это только косметическое изменение c.
  • T extends GenericAction<string, T["payload"]> является рекурсивным, но не обязательным; вместо этого вы можете заменить его на T extends GenericAction<string, unknown>, потому что любой T, назначаемый на GenericAction<string, unknown>, по необходимости будет назначаться на GenericAction<string, T["payload"]>
  • Поиск T["payload"] выполняется в вашей версии несколько раз; Есть разные способы избежать повторения этого поиска. Один из них - присвоить его новой переменной типа c generi P, значением по умолчанию которой является желаемое значение; это то, что я сделал с type GAC<T, P = T["payload"]> = ⋯. Другой способ - использовать условный вывод типа: type GAC<T> = T["payload"] extends infer P ? ⋯: never.
  • Поскольку обе ветви вашего условного типа выглядят как (⋯) => T, может быть возможно поместить условный тип в список параметров функции, чтобы избежать дублирования сигнатуры функции. Существует связь между списками параметров и кортежами , которую мы можем использовать для этого: Тип функции (x: X)=>void также может быть записан (...xs: [X])=>void; первый является функцией одного аргумента типа X, а второй - функцией, чей список аргументов представляет собой одноэлементный кортеж типа X. И тип функции (x?: X)=>void также может быть записан (...xs: [X?])=>void; первый является функцией одного необязательного аргумента типа X, а второй - функцией, список аргументов которой представляет собой одноэлементный необязательный кортеж типа X. Этот знак вопроса после типа в кортеже обозначает его как необязательный ... вы можете думать о [X?] как об объединении [] | [X].

Хорошо, надеюсь, это поможет вам дать некоторые варианты и направление. Удачи!

Детская площадка ссылка на код

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...