Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type errors with createSlice in TypeScript 3.4.1 #131

Closed
pat-son opened this issue Apr 8, 2019 · 9 comments · Fixed by #133
Closed

Type errors with createSlice in TypeScript 3.4.1 #131

pat-son opened this issue Apr 8, 2019 · 9 comments · Fixed by #133

Comments

@pat-son
Copy link

pat-son commented Apr 8, 2019

When the reducers in a createSlice have mixed payload action types, I get weird type errors as of TypeScript 3.4.1 (Maybe 3.4.0 as well, I didn't check).

image

It's like it's assuming that all PayloadActions it sees should be the same type as the first one.

Code for reproduction:

interface MyState {
    name: string;
    loading: boolean;
    count: number;
}

const INITIAL_STATE: MyState = {
    name: '',
    loading: true,
    count: 0,
}

const slice = createSlice({
    slice: 'mySlice',
    initialState: INITIAL_STATE,
    reducers: {
        setCount : (state, action: PayloadAction<number>) => { state.count = action.payload },
        setName: (state, action: PayloadAction<string>) => { state.name = action.payload },
        setLoaded: (state) => { state.loading = false; },
    }
})
@Rinaldo
Copy link

Rinaldo commented Apr 8, 2019

I'm also having issues with createSlice types.

const slice = createSlice({
    initialState: {
        data: []
    },
    reducers: {
        setData: (state, action: PayloadAction<any[]>) => {
            state.data = action.payload
        }
    }
})

The above produces an error: TS2322: Type 'any[]' is not assignable to type 'never[]'

@markerikson
Copy link
Collaborator

markerikson commented Apr 8, 2019

@denisw , @Jessidhia , @Dudeonyx : any thoughts?

@pat-son
Copy link
Author

pat-son commented Apr 8, 2019

@Rinaldo yours is a separate issue. The type of data is never[] - you need to give it a type with either an interface or a cast:

const slice = createSlice({
    initialState: {
        data: [] as any[]
    },
    reducers: {
        setData: (state, action: PayloadAction<any[]>) => {
            state.data = action.payload
        }
    }
})

//
// or
//

interface State {
    data: any[];
}

const initialState: State = {
    data: [],
}

const state = createSlice({
    initialState: initialState,
    reducers: {
        setData: (state, action: PayloadAction<any[]>) => {
            state.data = action.payload
        }
    }
})

@Rinaldo
Copy link

Rinaldo commented Apr 8, 2019

@pat-son I had tried the first option before posting and just now tried the second one. Neither of those snippets work for me, they both still produce the same error.

running redux-starter-kit 0.4.3 and typescript 3.4.2

@Dudeonyx
Copy link
Contributor

Dudeonyx commented Apr 9, 2019 via email

@Rinaldo
Copy link

Rinaldo commented Apr 9, 2019

@Dudeonyx That didn't seem to help, and I also noticed the same error with createReducer.

const initialState = {
    data: [],
}

const reducer = createReducer(initialState, {
    setData: (state, action: PayloadAction<any[]>) => {
        state.data = action.payload // TS2322: Type 'any[]' is not assignable to type 'never[]'
    }
})

It doesn't seem to matter whether the state is explicitly typed or not and it seems to only be a problem with arrays. Other types come through fine.

Should I open another issue or keep the discussion here?

@denisw
Copy link
Contributor

denisw commented Apr 9, 2019

Interestingly, the example works compiles fine in TypeScript 3.2.2 (the one we test against within redux-starter-kit), and the overall action type of the slice is inferred as PayloadAction<any>. However, in TypeScript 3.4 compilation fails as subscribed.

I suspect the change in behavior stems from a change in 3.4:

Higher order type inference from generic functions

TypeScript 3.4 can now produce generic function types when inference from other generic functions produces free type variables for inferences. This means many function composition patterns now work better in 3.4.

Sounds related, but I'm not 100% sure.

Anyway, a pragmatic solution would be to change the type signature of createSlice to expect PayloadAction<any> everywhere. Users of te function can still specify more precise action types for their case reducers as @pat-son has done, but there will be no weird type errors.

@denisw
Copy link
Contributor

denisw commented Apr 10, 2019

I think I found a way to restructure the typings so that the createSlice and createReducer type inference works better. I created a PR (#133), feel free to test whether it fixes your problem.

@markerikson
Copy link
Collaborator

I've been fully busy with React-Redux stuff (and real work!) lately, but I will try to swing through and deal with several outstanding RSK PRs / issues within the next few days.

markerikson pushed a commit that referenced this issue Apr 28, 2019
* Improve type inference of case reducers

Previously, the TypeScript compiler would reject case reducer maps
with different incompatible PayloadAction types. The case reducers
map and createReducer() / createSlice() types have now been
restructured to allow for better type inference.

Fixes #131

* Upgrade TypeScript and ESLint parser

Upgraded TypeScript to 3.4.3 and switches to the new TypeScript ESLint
parser.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants