Машинопись Таинственный перекресток - PullRequest
0 голосов
/ 15 февраля 2019

TLDR: Playground Repro

В моем приложении я определяю несколько модулей формы, которые выглядят примерно так:

const firstModule = {
    name: 'firstModule',
    mutation: () => {
        return (opts: {variables: {firstModuleArg: string}}) => {} 
    }
}

const secondModule = {
    name: 'secondModule',
    mutation: () => {
        return (opts: {variables: {secondModuleArg: number}}) => {} 
    }
}

Как видите, каждыйФункция мутации возвращает функцию, которая ожидает поле особой формы variables.

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

firstModule.mutation()({ variables: { firstModuleArg: 'test' } }); => ok

secondModule.mutation()({ variables: { secondModuleArg: 123 } }); => ok

Однако я также создаю центральный реестрэти формы, так что я могу искать их откуда-то так:

const forms = {
    firstModule,
    secondModule
}


const getFormConfig = (root: 'firstModule' | 'secondModule') => {
    const rootObj = forms[root];

    return rootObj;
}

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

const { mutation: firstModuleMutation } = getFormConfig('firstModule');

firstModuleMutation()({ variables: { firstModuleArg: '1234' } });

Typescript Error

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

Спасибо!

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Когда функция определена таким образом, TypeScript теряет связь между именем вашего модуля и типом возвращаемого значения мутации.

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

Сначала нам понадобятся несколько часто используемых помощников.

type ValueOf<T> = T[keyof T];
type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U;

Модель вашего домена:

/**
 * Type aliases.
 */
type Forms = typeof forms;
type Module = ValueOf<Forms>;

/**
 * The return type for `getFormConfig`.
 */
type TransformedModule<T extends Module> = Overwrite<T, { mutation: ReturnType<T['mutation']> }>;

Окончательное решение:

export function getFormConfig<K extends keyof Forms>(arg: K) {
  const module = forms[arg];

  return ({ ...module, mutation: module.mutation() }) as TransformedModule<Forms[K]>;
}

Использование:

getFormConfig('firstModule').mutation({ variables: { firstModuleArg: 'foo' } })
getFormConfig('secondModule').mutation({ variables: { secondModuleArg: 42 } });
0 голосов
/ 15 февраля 2019

Вы могли бы помочь компилятору с перегрузками:

function getFormConfig(root: 'firstModule'):
    typeof firstModule & { mutation: ReturnType<typeof firstModule.mutation> }
function getFormConfig(root: 'secondModule'):
    typeof secondModule & { mutation: ReturnType<typeof secondModule.mutation> }
function getFormConfig(root: 'firstModule' | 'secondModule') {
    const rootObj = forms[root];

    const mutation = rootObj.mutation();
    return {...rootObj, mutation}
}
...