Setting up a React, Next js app with TS for the first time and getting a beating at it.
TS throws below error on redux-saga
set up:
Property 'name' does not exist on type 'Input | DataPostGreeting | ErrorPostGreeting'. Property 'name' does not exist on type 'DataPostGreeting'
It's accurate that name
does not exist on type DataPostGreeting
, which is the type of the successful response, but it does exist in Input
The action in question is a POST to create a greeting on a test app.
I thought I had properly typed the payload as Input
which is the name
of the greeting, but TS does not seem happy with that. Even though it does recognizes Input
as part of the applicable types.
This is the saga with the error trigger highlighted:
/store/sagas/greetings.ts
import { all, call, put, takeLatest } from 'redux-saga/effects';
import { actionPostGreetingOk, actionPostGreetingError } from '../actions/creators';
import { Actions } from '../actions/names';
import { ActionTypes } from '../actions/types';
import { apiQl } from 'lib/functions';
function* postGreeting(action: ActionTypes) {
const queryQl = `mutation createGreeting(
$name: String!
) {
createGreeting(input: {
name: $name
}) {
greeting {
id
}
}
}`;
const variables = {
name: action.payload.name, // *** ERROR IS THROWN HERE ***
};
try {
const data = yield call(apiQl, queryQl, variables);
if (data.errors) {
yield put(
actionPostGreetingError({
error: data.errors,
}),
);
} else {
yield put(
actionPostGreetingOk({
greeting: data.data.createGreeting,
}),
);
}
} catch (error) {
if (error.response === undefined || error.code === 'ECONNABORTED') {
console.log('ERROR RESPONSE UNDEFINED, ABORTED');
}
}
export default function* greeting() {
yield all([takeLatest(Actions.POST_GREETING, postGreeting)]);
}
On the types file:
...
export interface Input {
name: string;
}
export interface ActionPostGreeting {
type: typeof Actions.POST_GREETING;
payload: Input;
}
...
export type ActionTypes =
| ActionPostGreeting
| ActionPostGreetingInit
| ActionPostGreetingOk
| ActionPostGreetingError
| ActionHydrate;
The action creator:
export const actionPostGreeting = (payload: Input): ActionPostGreeting => {
return {
type: Actions.POST_GREETING,
payload,
};
};
You are passing the whole ActionTypes
union to your saga, but your function should only take a specific payload type (e.g. ActionPostGreeting
). Otherwise it means your saga could be called with any payload, to fix your issue you can restrict the type like this:
function* postGreeting(action: ActionPostGreeting) {
// do stuff
const variables = {
name: action.payload.name, // will be good
};
}