Столкнулся с этим вопросом, и я подумал, что добавлю пару объяснений на случай, если вам все еще интересно, и если кто-нибудь столкнется с этим в будущем!
Во-первых - в вашем примере вы слишком много обдумываете в терминах возвращаемого типа.
Если вы хотите вывести что-то в качестве типа, в котором оно передается (например, здесь вы хотите, чтобы ваше действие возвращалось в том виде, в каком оно есть), вы просто возвращаете тот же generi c, который вы переходите - как в ответе сказано:
function foo<A>(val: A): A {
return val;
}
Если я вызываю foo () с номером, я получаю его обратно. Если я вызываю его с определенным типом действия c, то происходит то же самое. Вот почему вам просто нужен return type OperatorFunction<A, A>
- то же самое, то же самое.
Второй - как работает ofType?
Ключевым моментом здесь является то, что вам нужен некоторый набор действий который вы сужаете.
Использование createAction позаботится об этом за вас, но, например, я создам это вручную.
type FooAction = { type: 'FOO_ACTION' };
type BarAction = { type: 'BAR_ACTION' };
// This type gets built by you using createAction - this is your Action type
type MyActions = FooAction | BarAction;
Далее нам нужен тип, который будет возьмите наш набор действий (MyActions
) и сузите его до определенного c действия в зависимости от типа.
type NarrowActionType<T extends { type: any }, K extends string> = T extends { type: K }
? T
: never;
Мы можем проверить, что это работает:
type NarrowedActionTest = NarrowActionType<MyActions, 'FOO_ACTION'>;
![Verifying NarrowedActionTest works in TS playground](https://i.stack.imgur.com/QtfIl.png)
ofType is a higher order function which first accepts a string, and then the observable stream to operate on. I'm not going to use observables to keep it simpler, but it's the same principle.
In essence we want something along the lines of (type: string) => (action: Action) => action is NarrowActionType
for the type signature.
- NarrowActionType needs the overall action type as it's first type parameter, which we will call
A
- NarrowActionType needs the string literal type which we are using to narrow with, which we will call
T
- T is going to be a string, so
T
extends string
- We only know the type of
T
to begin with, and then the type of A
once the object stream is applied, so let's use one generic parameter at each function application
- The function is going to ultimately check if
A.type
is the same as type. So we should enforce this exists, with A extends { type: any }
function isOfType<T extends string>(type: T) {
return <A extends { type: any }>(action: A): action is NarrowActionType<A, T> => {
return action.type === type
}
}
Теперь мы можем протестировать эту функцию на типе MyActions и посмотреть, сможет ли она сузить вывод:
const myAction: MyActions = { type: 'FOO_ACTION' };
const isFooAction = isOfType('FOO_ACTION')(myAction);
if (isOfType('FOO_ACTION')(myAction)) {
type myNarrowedAction = typeof myAction; // is FooAction
}
Полная ссылка на игровую площадку здесь: https://www.typescriptlang.org/play/#code / C4TwDgpgBAcghgJwQewO4EEDGwCWyB2AKuBADyFQQAewE + AJgM5QDeUokAXFHPiFAF8ANFADSlGnSZRGwBDnwBzAHxQAvFArVaDZmw4Ru4gQCgoUAPyazUbvggA3CAgDcJkwagAxZMiy4CdVZ2Em4Aci8AeUiAfXQAYUIASUiYMME3TwAhRH88fCD9UKgwrPQAJTjElLSM9xMAegbNAAscZk9FCGBmACMAVxwAG2AoXv4QZH6ofsYFRShMBAg4WjzAgFp2NuZ2qEn + hCh1goMPEigAWRAT5g0fP2 x8qAAfKByEE7dzyFhEFFQEHoJ0IEFkQXgSDQIJIpGutxEEWiVWSqTCym + ADN + vgnoF2pFMcRIOQJDppLJ5EplAAKAzcQgASlYNnMy2AhwKpHQZKkehCXB4fEEtLgePw3HQjO4YoCBT2kIBMJJ6BEhFUalULFZ5l17M5PHFADpPGozQKIDrTKYTJgCOCALY3cXceHiu7BeklKKxBKo2oCNx2-Dg9oPE5BAlEkg0pG + 6poxk0p0nRnfHCYqA0qPEiCxn0omphJMp8WM5na3UWqBOxVoIERjQGZCZ0tylxQJpQPbh8UmUxAA