0

I have the following helper method that returns a wrapped react component.

export function wrapComponentInContext<T extends object = {}>(
  Comp: React.FunctionComponent<T>, 
  props: T = {}) { // ERROR: Type '{}' is not assignable to type 'T'

  const mockSetter = jest.fn(() => { });    
  const mockContext: ContextDefaultValue = ["context", mockSetter];

  return (
    <Provider value={mockContext}>
      <Comp {...props}/>
    </Provider>
  );
}

I want to default to an empty object if no argument is supplied.

Here is an even simpler example

So it seems an empty object is not of type {} which is confusing.

Why

0

1 Answer 1

2

A generic function needs to be valid for any possible T passed into the function. T extends object means T can be any object type, so it could for example be { foo: string } and {} would not be a valid default for this type.

The default type for the type parameter in no way correlates with the default for the parameter. You can call with an explicit type argument and without a default thus producing a conflict between the default value {} and T passed in. Or you can just omit the default and pass in a component with required props:

declare function comp(o: { p: string }): void;
wrapComponentInContext(comp)

You can use a type assertion to force {} into T:

export function wrapComponentInContext<T extends object = {}>(Comp: React.FunctionComponent<T>, props: T = {} as T) {

}

But this will expose you to the potential issues I highlighted above. You can add a dedicated overload for a component for which {} is a valid default, although getting it to work as expected requires a bit of conditional types because of the contravariant nature of function parameters:

declare function compOptional(o: { p?: string }): void;
declare function comp(o: { p: string }): void;

export function wrapComponentInContext<T>(Comp: React.FunctionComponent<T> & ({} extends T ? {} : "Provide default props as component requires some"))
export function wrapComponentInContext<T extends object>(Comp: React.FunctionComponent<T>, props: T)
export function wrapComponentInContext<T extends object = {}>(Comp: React.FunctionComponent<T>, props: T = {} as T) {

}
wrapComponentInContext(comp) // Type '(o: { p: string; }) => void' is not assignable to type '"Provide default props as component requires some"'.
wrapComponentInContext(compOptional)
wrapComponentInContext(comp, { p: "" })
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.