Flowtype: как правильно использовать $ ObjMap для создания цепочки всех функций? - PullRequest
0 голосов
/ 08 июля 2019

Я работаю над некоторым пакетом JS и хочу предоставить отдельные определения типа потока как index.js.flow, потому что внутреннее поведение немного отличается.

У меня есть эта функция для создания определения компонента

function defineComponent(name, createFunc);

createFunc - это функция, которая захватывает элементы и возвращает объект, содержащий определенные пользователем действия над этим компонентом

, поэтому вы можете вызвать defineComponent следующим образом:

const loginForm = defineComponent("login form", () => {
  ...
  ...
  return {
    fillUsername: () => { ...doesn't matter what is return type... },
    fillPassword: () => { ...doesn't matter what is return type... }
  };
});

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

loginForm
  .fillUsername()
  .fillPassword()

Итак, внутренне defineComponent обернет каждое пользовательское действие следующим образом для создания цепочки способностей:

function defineComponent(..., createFunc) {
  const actions = createFunc(...);

  return actions.map(action => {
    return (...args) => {
      action(...args);
      return actions;
    }
  })
}

Я уже пробовал это (все моикод проверки):

type ComponentType<T> = $ObjMap<T, <V>((V) => any) => V => ComponentType<T>>;

declare function defineComponent<T>(
  name: string,
  createFunc: () => T
): ComponentType<T>;

const Component = defineComponent("foo", () => {
  return {
    fooAction: () => {},
    barAction: () => {}
  };
});

Component.fooAction().barAction()

Я перехожу к потоку No errors!, но поток не выдает ошибок, даже когда я делаю что-то вроде

Component.fooAction.barAction()

А также VS Code не обеспечивает автозаполнение выше этого: /

Спасибо!

1 Ответ

0 голосов
/ 09 июля 2019

Это то, что я смог придумать.Основная идея заключается в том, что мы отображаем исходный тип значения V => mixed (то есть унарную функцию) на V => T (то есть тот же единственный аргумент, но теперь он возвращает карту действия T).

function chainable<T: { [actionName: string]: Function }>(
  actions: T
): $ObjMap<T, <V>(V => mixed) => (V => T)> {
  return Object.keys(actions).reduce((newActions, actionName) => {
    newActions[actionName] = function(...args) {
      actions[actionName](...args);
      return this;
    }
    return newActions;
  }, {});
}

Попробуйте Flow

ПРИМЕЧАНИЕ : Я не думаю, что это абсолютно безопасно для типов, потому что this на самом деле не типа T.Но я не думаю, что у Flow есть сложность аннотировать тип this в значениях newActions.Кроме того, это работает, только если все действия имеют унарные функции для значений.К сожалению, у Flow нет словаря для описания обобщенных вариантов (см. https://github.com/microsoft/TypeScript/issues/5453 для получения информации о том, что это означает и как его можно использовать).

...