2

In TypeScript is there a way for useContext within the following to pick and return the value type from from Provider?

function Provider<Props = {value: number}>(props: Props) { }
function useContext<Value>(context: Context<Value>): Pick<Value, 'value'> { return 0 }

Such that "Consumer" will return the type: number when used as follows

function Consumer<Props>(props: Props) { return useContext(Provider) }

...For additional context:

interface Component<Props = {}> { (props: Properties<Props>): Node }
interface Context<Value> extends Component<{value: Value}> {}

Or alternatively, given

function Provider({value, children}: {value: string, children: any}) {
  return h(Context, {value: 'value'}, children)
}

const value = useContext(Provider)

How would one attribute the constant "value" to the "value" found in the object {value: 'value'} assuming that the function "h" returns an interface:

interface {type: Context, props: {value: 'value}, children: children}

I've tried to Pick, props> where Type is "Provider" then Pick from the result of that Pick, props>, 'value'>.

That however didn't seem to work.

1 Answer 1

3

There is a nifty way to extract property types called 'lookup types' (TypeScript 2.1 Notes). The syntax is:

MyType['value'] // number

Where MyType contains a property value: number.


Edit: I'm having trouble following your example, I tried expanding useContext's 'context' parameter and ended up with this:

   function useContext<Value>(context: Context<Value>): Pick<Value, 'value'>;
=> function useContext<Value>(context: Component<{value: Value}>): Pick<Value, 'value'>
=> function useContext<Value>(context: (props: Properties<{value: Value}>) => Node): Pick<Value, 'value'>

If we follow the Value type to the 3rd expansion we see that there is no constraint; nothing telling the compiler that the Value type must have a 'value' property. The only way for the Typescript compiler to return a type from useContext(...) based on Value["value"] is if there's some constraint telling the compiler that 'value' exists on the type.

One option, if you add a type constraint <Props extends {value: number} = {value: number}> to Component and Provider the compiler will be able infer that the props has a 'value' property.

Another option, explicitly tell the compiler which property you already know to exist using keyof and passing in the key literal string (added 'key' parameter, and changed return type to Pick<Value, K>):

function useContext<Value, K extends keyof Value>(context: Context<Value>, key: K): Pick<Value, K> {
  // ...
}

var value = useContext(Provider, 'value');
Sign up to request clarification or add additional context in comments.

2 Comments

I've updated the question with more context. Yes lookup types as i understand them won't work in this case, at least as far as i've tried.
Thanks, lookup types is what i needed, i was under the wrong impression about what Pick does in typescript.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.