Я пытаюсь создать общую функцию, которая будет создавать довольно распространенные эффекты, поэтому я смогу передать только конфигурацию, и она создаст эффект.
Вот некоторые импортированные данные из NgRx:
import { ActionCreator } from '@ngrx/store';
import { createActionGroup, props } from '@ngrx/store';
и одна ActionGroup для целей тестирования:
export const featureActions = createActionGroup({
source: 'MyGroup',
events: {
'Update Entity': props<{ data: { updateName: string } }>(),
'Delete Entity': props<{ data: { deleteName: string } }>(),
},
});
Для этого я создал файл конфигурации, который принимает действие ngrx (ActionCreator) и одну функцию сопоставления.
export type Config<AC extends ActionCreator> = {
action: AC;
mapping: (data: ReturnType<AC>) => string;
};
Сама фабричная функция принимает массив этих конфигов:
export function createMyEffects<AC extends ActionCreator>(
effects: Config<AC>[]
) {
// doing nothing, I guess it is not relevant
console.info(effects);
}
Проблема возникает при вызове функции:
createMyEffects([
{
action: featureActions.updateEntity,
mapping: (updateData) => updateData.data.updateName, // place #2
},
{
// Issue is that it thinks that this action should be the same as the first
action: featureActions.deleteEntity, // the place #1
mapping: (deleteData) => deleteData.data.deleteName, // place #3
},
]);
Итак, с моим объявлением функции TS выбрасывает меня на место №1, что typeof FeatureAtions.deleteEntity
не может быть присвоен typeof FeatureAtions.updateEntity
.
Поэтому я изменил его на
export function createMyEffects<AC extends ActionCreator[]>(
effects: Config<AC[number]>[],
)
и в данном случае ошибок нет, но теперь я теряю вывод типа в местах №2 и №3. deleteData
и updateData
аргументы выводят тип Object
вместо соответствующих ReturnType< FeatureAtions.deleteEntity>
и ReturnType<FeatureAtions.updateEntity>
.
Как я могу обеспечить вывод типа в этом случае?
УПД: Вот ссылка stackblits с env
Спасибо за обновления, но кое-чего еще не хватает. Пожалуйста, опробуйте свой собственный пример кода в автономной IDE и исправьте любые опечатки, несоответствия или недостающие вещи, о которых вы не спрашиваете. (например, data
? Toast
? updateName
? и еще что-нибудь?)
Я вижу три ошибки, где вы упоминаете три ошибки, но все эти ошибки — опечатки. Вы пишете actions
вместо action
и data
вместо updateData
и deleteData
. И updateName
и deleteName
больше нигде в коде не встречаются. Когда я попросил вас опробовать свой собственный код в автономной IDE… вы это сделали? Я действительно пытаюсь помочь, но это очень сложно, когда мне приходится отлаживать способ решения проблемы.
@jcalz Я добавил ссылку на stackblitz, надеюсь, это поможет воспроизвести задачу.
Но код должен быть здесь в виде открытого текста. У меня нет прав копировать сюда код из вашего stackblitz. Не могли бы вы отредактировать, чтобы это сделать? И даже в этом стекеблице я вижу actionMapping
где mapping
ожидается? Я не знаю, как еще попросить вас исправить опечатки, прежде чем привлекать внимание других к коду. Все, что он делает, это замедляет людей и заставляет их решать проблемы, о которых вы даже не пытаетесь спросить. Не могли бы вы отредактировать приведенный здесь код в виде обычного текста и четырежды проверить его, чтобы убедиться в отсутствии опечаток?
(см. предыдущий комментарий.) Соответствует ли этот подход вашим потребностям? Если да, я напишу ответ, и если вы дадите мне разрешение, я также отредактирую код вашего вопроса, чтобы предоставить соответствующий минимально воспроизводимый пример без опечаток или недостающих объявлений. Если нет, то что мне не хватает?
@jcalz, да, спасибо, твой подход соответствует тому, что я искал. Извините за опечатки, и вы определенно можете отредактировать мой вопрос.
Спасибо! Я напишу ответ, когда у меня будет возможность.
@jcalz, единственное, что осталось, это то, что даже ваш пример не выводит типы машинописного текста v5.2.2. Есть ли у вас идеи, почему и есть ли способ справиться с этим в версии 5.2.2, или единственный способ — перейти на версию 5.4.5?
Я не знаю, это действительно выходит за рамки. Я не вижу в вопросе ничего, указывающего конкретную версию TypeScript. Я подожду и не буду писать здесь ответ, пока не узнаю, достаточно ли это важно для вас, чтобы редактировать вопрос, чтобы указать TS5.2. Дайте мне знать, как действовать.
Я понятия не имел, что эта версия может иметь отношение к проблеме. Я приму ваш ответ, потому что независимо от версии ваш код работает, а мой — нет. Было бы здорово, если бы у вас были какие-нибудь идеи относительно того, как я мог бы сделать это с помощью v5.2.2.
Конечно, кажется, что что-то изменилось в TS5.4, чтобы он начал работать, но в примечаниях к выпуску TS5.4 это не упоминается, а это означает, что мне нужно начать копать, чтобы увидеть, какой именно коммит изменил ситуацию, и посмотреть, с чем это связано. прежде чем я смог даже предположить, как заставить его работать в предыдущих версиях. Я не думаю, что смогу потратить столько времени на его просмотр, по крайней мере, не сейчас.
Нет, нет. Огромное спасибо, все в порядке.
Обратите внимание, что соответствующее изменение обсуждается здесь . Если вам необходимо использовать TS5.2, я бы предложил использовать параметр rest вместо ввода массива, как показано в этой ссылке на игровую площадку. Я, вероятно, не буду включать ничего из этого в свой ответ.
Потрясающий. Спасибо за ваши усилия. Будем ждать вашего ответа, чтобы отметить вопрос как решенный.
Если вы хотите, чтобы каждый элемент входного массива effects
имел свой собственный аргумент типа для Config<>
, тогда вам нужно будет сделать функцию универсальной в кортежном типе этих аргументов типа и сделать effects
сопоставленным тип кортежа:
function createMyEffects<AC extends ActionCreator[]>(
effects: { [I in keyof AC]: Config<AC[I]> }
) {
console.info(effects);
}
Тогда это будет работать по желанию, по крайней мере, для TypeScript 5.4 и выше:
createMyEffects([
{
action: featureActions.updateEntity,
mapping: (updateData) => updateData.data.updateName,
},
{
action: featureActions.deleteEntity,
mapping: (deleteData) => deleteData.data.deleteName,
},
]);
К сожалению, до TypeScript 5.4 это не работало должным образом... TypeScript имеет возможность делать выводы из сопоставленных типов, но когда ввод функции представляет собой литерал массива это работало неправильно. Это было исправлено в microsoft/TypeScript#56555.
Это минимально воспроизводимый пример ? Являются ли
FeatureAtions
,ActionCreator
иToastEffectConfig
частными типами или они экспортируются с помощью angular/ngrx? Если они частные, пожалуйста отредактируйте вопрос, чтобы объявить их (а еще лучше удалите их и замените на родные TS). Если они связаны с технологией, от которой зависит вопрос, пожалуйста,import
укажите их явно в примере. Цель состоит в том, чтобы мы могли скопировать и вставить ваш код в наши собственные IDE, сразу же увидеть вашу проблему и приступить к работе над ней.