0

In this example i have created 2 typed objects, toggle and counter which both conform to the Config interface, each passing their own State and Action parameter types.

My question is, how can i access these Config types and their associated State and Action params inside my createStore function body? I have no idea how to type the argument so that i don't lose that information?

I have read through the TS docs and im thinking this is something generics might help with?

Samuel
  • 2,485
  • 5
  • 30
  • 40
  • Could you put your code in the text of the question and make sure it's a [mcve]? For example, what type is `createStore()` supposed to return? Inside the implementation of `createStore()` you wouldn't be able to get *much* more expressive than `Config` for each property. But from the caller's point of view it may be important to preserve the mapping from key to `Config` for some `S` and `A`... depending on what `createStore()` returns. – jcalz Jul 26 '19 at 13:39
  • Anyway this is close to a canonical use case for [existential types](https://stackoverflow.com/questions/292274/what-is-an-existential-type), which [aren't supported directly in TypeScript](https://github.com/Microsoft/TypeScript/issues/14466). There are ways to encode existential types using regular generics, but they are clunky and you might rather just use `Config` inside the implementation. If you edit a use case into your code (and put your code here) I might have suggestions. Good luck! – jcalz Jul 26 '19 at 14:05
  • Thanks for your comments @jcalz. i have a full working example here where i feel like im getting close, but im not sure how to get around the 'context is being used before its been defined' error im getting in my return. I need it to be a key of the object i pass in, so it wont let me initialise it to an empty object? https://codesandbox.io/s/reduxified-machine-package-qgevk – Samuel Jul 26 '19 at 15:00
  • That's a different issue, isn't it? I don't really have react/redux expertise, so I wouldn't hazard a guess as to how to fix it. If you want to get this question here answered, you should consider putting the relevant code in the text of the question. Good luck again! – jcalz Jul 26 '19 at 15:22
  • For anyone interested, i found out how to unpack Params from a Type using this fantastic article, exactly what i needed: https://link.medium.com/nkLcM7L9GY – Samuel Jul 29 '19 at 07:40

2 Answers2

0

If I've understood correctly... you can specify the types for toggle and counter like this -

type ToggleType = typeof toggle;
type CounterType = typeof counter;

And then you can inline the obj parameter for your function -

const createStore = (obj: { toggle: ToggleType, counter: CounterType  }) => {
    const { toggle, counter } = obj;
}

Edit after comments: Something like this may help, too, if you don't always have a toggle and a counter property (i.e. the properties of obj are arbitrary) -

type CreateStoreContext = {
    [key: string]: Config<any, any>
}

const createStore = (obj: CreateStoreContext) => {
    Object.keys(obj).forEach(key => {    // Key is a string
        const config = obj[key];         // config is a Config<any, any>
    })

    // ....
}

The difficulty though is that you won't know what the types are for State and Actions for each property of obj - but at least you know it conforms to a Config interface.

gerrod
  • 6,119
  • 6
  • 33
  • 45
  • Hi, thanks for this. The problem is i want to avoid being that specific in my typing for the createStore function. This will eventually be extracted into its own npm module, so i want to be more generic and somehow capture the `Config` that is passed in for each one. – Samuel Jul 26 '19 at 10:55
  • Will the `obj` parameter always have a `toggle` and `counter` property? Or are the properties arbitrary? – gerrod Jul 26 '19 at 11:01
  • Yeh, so the `obj` param could be made up of any key, as long as the value always conforms to the `Config` interface. – Samuel Jul 26 '19 at 11:04
0

I found this article which explains how to go about extracting param values from a type.

https://itnext.io/typescript-extract-unpack-a-type-from-a-generic-baca7af14e51

This makes use of conditional types, the basic syntax is as follows:

type ExtractState<C> = C extends Config<infer State, infer Action> ? State : never;

Samuel
  • 2,485
  • 5
  • 30
  • 40