, 6 tweets, 3 min read
My Authors
Read all threads
While last #TypeScriptTuesday we looked at #TypeScript Generics Basics, today we continue where we left off, by taking a closer look at type argument inference, pitfalls and workarounds. We will take a look at a simplified version of #redux-toolkit's `createAction` function.
🧵👇 interface PayloadAction<P, T = string> {<br />
  type: T;<br />
  payload: P;<br />
}<br />
<br />
type ActionCreator<P, T> = (payload: P) => PayloadAction<P, T>;<br />
<br />
function createAction<P, T = string>(type: T): ActionCreator<P, T> {<br />
  return (payload: P) => ({<br />
    type,<br />
    payload<br />
  });<br />
}
Here, we call this function three ways:

1. With explicit type arguments. Everything is fine.
2. With inferred type arguments. P cannot be inferred, because it does not relate to any method argument.
3. With one explicit type argument. But why is the second argument not inferred? function createAction<P, T = string>(type: T): ActionCreator<P, T> {<br />
  /* ... */<br />
}<br />
<br />
const type =
// ActionCreator
const incrementAction = createAction(type);

// ActionCreator
const actionCreator2 = createAction(type);

// ActionCreator
const actionCreator3 = createAction(type);" src="/images/1px.png" data-src="https://pbs.twimg.com/media/EOQ6FriXUAEYJDD.jpg">
This is because #TypeScript cannot mix explicit and inferred type arguments.
There is a PR for that at github.com/microsoft/Type…, but there is still discussion on what syntax to use.
Let's just assume that this is impossible and try to work around it.
One possible solution would be to wrap it in yet another function, let's call this "Type Argument Currying".
Here `createAction` infers `T` and `withPayload` is called with `number` explicitly.
But this requires a change in our existing runtime code, and it is a bit weird to use. function createAction<T = string>(type: T) {<br />
  return function withPayload<P>(): ActionCreator<P, T> {<br />
    return (payload: P) => ({<br />
      type,<br />
      payload<br />
    });<br />
  };<br />
}<br />
<br />
// ActionCreator<number,
const incrementAction = createAction("increment" as const)();" src="/images/1px.png" data-src="https://pbs.twimg.com/media/EOQ6Gb_XkAE6m5W.jpg">
So what did we do in #redux-toolkit?
Actually, our `createAction` function can take an optional second `prepare` argument to modify the payload beforehand.
Here we just create a helper fn that captures a type and returns a `prepare` function that just passes the payload through. type PrepareAction<P> = (...args: any[] ) => { payload: P };<br />
<br />
function createAction<P, T = string>(type: T, prepare?: PrepareAction<P>): ActionCreator<P, T> {<br />
  return (payload: P) => ({<br />
    type,<br />
    payload<br />
  });<br />
}<br />
<br />
function withPayloadType<T>() {<br />
  return (t: T) => ({ payload: t });<br />
}<br />
<br />
const incrementAction = createAction(());" src="/images/1px.png" data-src="https://pbs.twimg.com/media/EOQ6HCXXUAYaEIi.jpg">
So, you now know two way to combine explicit and inferred type arguments - and that's it for today.

Next week, you will learn how you can add restrictions to your type parameters.
After all, right now you could pass any object as `T` parameter, and we don't want that.
Missing some Tweet in this thread? You can try to force a refresh.

Enjoying this thread?

Keep Current with Lenz Weber

Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!