Typescript: Возврат союза на основе ReturnTypes в объекте

avatar
Kyle Johnson
8 августа 2021 в 17:34
45
1
3

Мой исходный код выглядит следующим образом. Он позволяет мне определять тип данных на основе типа при переключении на действие:ActionType.

enum Actions {
  GET_MESSAGES,
  GET_MESSAGES_LOADED
}

//@ts-ignore
const AppActions = {
  getMessages() {
    return {
      type: Actions.GET_MESSAGES,
      data:{id: 1}
    };
  },
  getMessagesLoaded() {
    return {
      type: Actions.GET_MESSAGES_LOADED,
      data:{messages: ['asdf']}
    };
  }
};

type ActionType = ReturnType<typeof AppActions[keyof typeof AppActions]>;


const func = (action:ActionType) => {
  // @ts-ignore
  switch (action.type) {
      case Actions.GET_MESSAGES:
          console.log(action.data.id) //Should pass
          break
      case Actions.GET_MESSAGES_LOADED:
        console.log(action.data.messages) //Should pass
          break;
      case Actions.GET_MESSAGES_ERROR: // Should throw typescript error
      // default:
      //   break;
  }
};

Я хотел бы знать, могу ли я создать объединение ActionType динамически, сопоставляя ключи AppActions?

Самый близкий ответ

Ответ @Elias на данный момент type ActionType = ReturnType<typeof AppActions[keyof typeof AppActions]>; вырезает здесь большую часть наворотов.

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

Источник
Raz Luvaton
8 августа 2021 в 17:47
0

Решит ли это для вас type ReturnTypeOfKeysOfUnion<T> = T extends T ? ReturnType<typeof AppActions[T]> : never;?

Elias
8 августа 2021 в 17:56
1

@RazLuvaton Как это работает? Если вы посмотрите на мое решение, его действительно легко понять по сравнению с этим. Я не говорю, что у вас плохо, я искренне заинтересован.

Ingo Bürk
8 августа 2021 в 17:59
2

@Elias Это решение работает с тем фактом, что условные типы поверх общих союзов становятся дистрибутивными: typescriptlang.org/docs/handbook/2/…

Raz Luvaton
8 августа 2021 в 18:00
0

Мне нравится ваш уважительный комментарий!

Elias
8 августа 2021 в 18:08
0

Похоже, это выше моей головы... @IngoBürk, но спасибо за ссылку на документ!

Elias
8 августа 2021 в 18:08
0

@RazLuvaton Я не уверен, почему, но он сообщает об ошибке для меня :( stackblitz.com/edit/typescript-c7emdb?file=index.ts

Raz Luvaton
8 августа 2021 в 18:12
1

Попробуйте вместо этого - type ReturnTypeOfKeysOfUnion<T> = T extends keyof typeof AppActions ? ReturnType<typeof AppActions[T]> : never;

Raz Luvaton
8 августа 2021 в 18:13
1

Первый написанный мной тип я не проверял (писал на телефон 😉)

Elias
8 августа 2021 в 18:17
0

@RazLuvaton Как его инициализировать? let m: ReturnTypeOfKeysOfUnion = AppActions.getMessagesLoaded(); не будет работать из-за отсутствия аргумента типа. Это особенно важно, поскольку мой ответ кажется недействительным. coderhelper.com/questions/68703207/…

Raz Luvaton
8 августа 2021 в 18:24
0

Я вижу, что это не работает, у меня нет идей 🤷🏻‍♂️

Elias
8 августа 2021 в 18:27
0

@RazLuvaton Честно говоря, это мой «ответ наизусть», но на самом деле это не ответ на вопрос coderhelper.com/questions/68703207/…

Ответы (1)

avatar
Elias
8 августа 2021 в 17:48
1

Этот ответ работает при извлечении типа, но защита типов не может разрешить и раскрыть базовый тип!

enter image description here

enter image description here

Ансер

type ActionType = ReturnType<typeof AppActions[keyof typeof AppActions]>;

Вам даже не нужно указывать возвращаемый тип функций:

const AppActions = {
    getMessages() {
        return {
            messages: ["asdf"],
        };
    },
    getMessagesLoaded() {
        return {
            loadedMessages: [1],
        }
    },
};
Kyle Johnson
8 августа 2021 в 18:01
0

Хм, это кажется таким близким, может быть, это моя IDE, но, похоже, она не определяет тип данных. Я скорректировал свой вопрос, чтобы сделать его немного проще.

Elias
8 августа 2021 в 18:14
0

Ха, ты прав! Я предполагаю, что, поскольку typescript не может определить базовый тип в коммутаторе, он по-прежнему имеет тип ActionType даже после защиты типа. Боюсь, здесь я не смогу вам помочь :(

Kyle Johnson
8 августа 2021 в 18:24
0

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

Elias
8 августа 2021 в 18:25
0

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

Kyle Johnson
8 августа 2021 в 18:27
0

Возможно, вы правы, у меня есть cli, который пишет весь этот код, так что это не имеет большого значения. Ваше решение ActionType в любом случае избавляет от большей части раздувания!

Elias
8 августа 2021 в 18:28
0

@KyleJohnson Мне очень жаль, что я не могу больше помочь

Elias
8 августа 2021 в 18:34
0

@KyleJohnson Возможно, кто-то более опытный, чем я, может сказать, действительно ли это ошибка машинописного текста? Я бы предположил, что это должно разрешить {loadedMessages: ...

Kyle Johnson
8 августа 2021 в 18:43
0

Может быть, так кажется, что вы правы! Возможно, это слишком дорого, чтобы обнаружить это.