Lenz Weber Profile picture
Jan 21, 2020 6 tweets 3 min read
Last #TypeScriptTuesday, we left off with a version of #redux-toolkit's `createAction` method that could be used with a mix of inferred and explicit #TypeScript Generic Arguments.
But that method would still take every `type` - including objects. Let's see how to restrict that.
This can be solved by using the `extends` keyword, which allows us to restrict a Type Argument. So here, we state that out `T` argument always has to be a valid `string`.
You could always override that restriction by using `any`.
But `extends` can do more than that...
Not only can you use any interface in `extends`, you can also reference other generic parameters.
This can - among other things - be used to "pick" types from another generic type. Before conditional types, this was the common way to do things like this:
And then there's this one weird trick: in #TypeScript, a generic argument can reference _itself_ in it's extends clause.
For example, this allows to restrict generic arguments to very explicit mapped types with an association between keys and values. type CaseReducers<State, ReducerMap> = {   [Type in keyof ReducerMap]: <A extends PayloadAction<any, Type>>(     oldState: State,     action: A   ) => State; };  function createReducer<S, M extends CaseReducers<S, M>>(   initialState: S,   reducerMap: M ): Reducer<S> {   // let's skip the implementation ;)   return () => initialState; }
And that's it for now with Generics.
Next week, we're going to take a deeper look at Interfaces. See you then!

For now, if you want to play around with the examples from this week, here's a TypeScript playground:

typescriptlang.org/play/#code/CYU…
@threadreaderapp rollup please

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with Lenz Weber

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!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @phry

Jan 28, 2020
This #TypeScriptTuesday, we're going to take a look at #TypeScript's interfaces.
Interfaces are different from types and both have their strengths in different situations.
Let's take a look.
This is just some interface definition - again an example from the #redux types:
🧵👇 interface Action {<br />
  type: string;<br />
}
An interface can also extend another interface.
Not only that, but also some (but not all) types.

The rule of thumb here is: if the type is well-known and could be written as an interface, it can be extended. // extending multiple interfaces is possible<br />
  interface StringPayloadActionWithError extends Action, WithErrorAttribute {<br />
    payload: string;<br />
  }<br />
<br />
  /**<br />
   * This can be resolved to { type: string; payload: string }, which<br />
   * could be expressed as an interface, so it can be extended.<br />
   */<br />
  interface StringPayloadAction extends Omit<StringPayloadActionWithError, {
meta: number;
}" src="/images/1px.png" data-src="https://pbs.twimg.com/media/EPZFwGmWkAEwwKG.jpg">
Another feature or Interfaces are index signatures. Interfaces can be indexed only by string or number, not by union types. You need Mapped Types for that.
If you index by string and number, the value indexed by number has to be a subset of the value indexed by string. interface SomethingElse {<br />
  [key: string]: string | number;<br />
  [key: number]: number;<br />
}<br />
<br />
interface InvalidInterface {<br />
  [key: string]: string;<br />
  // Error: An index signature parameter type cannot be a union type. Consider using a mapped object type instead.ts(1337)<br />
  [key: // Error: Numeric index type 'number' is not assignable to string index type 'string'.ts(2413)
[key: number]: number;
}
" src="/images/1px.png" data-src="https://pbs.twimg.com/media/EPZFw8KWsAMbDJi.jpg">
Read 7 tweets
Jan 14, 2020
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.
Read 6 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


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

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

Become Premium

Don't want to be a Premium member but still want to support us?

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

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us on Twitter!

:(