I wrote this higher-order component (HOC):
function withLoading<T>(WrappedComponent: ComponentType<T>) {
return function ({ isLoading, ...props }: { isLoading: boolean } & T) {
return isLoading ? <p>Loading…</p> : <WrappedComponent {...props} />;
};
}
But TypeScript complains about <WrappedComponent {...props} />
:
Type 'Omit<{ isLoading: boolean; } & T, "isLoading">' is not assignable to type 'IntrinsicAttributes & T'.
Type 'Omit<{ isLoading: boolean; } & T, "isLoading">' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'Omit<{ isLoading: boolean; } & T, "isLoading">'.(2322)
What am I doing wrong?
Omit<{ isLoading: boolean } & T, 'isLoading'>
is not assignable to T
because it is not a subtype of T
; it is a supertype of T
since we omit a property. See this answer.
When T
has no { isLoading: boolean }
property, Omit<{ isLoading: boolean } & T, 'isLoading'>
is equal to T
(here Y
is true
):
type X<T> = Omit<{ isLoading: boolean } & T, 'isLoading'>;
type Y = X<{}> extends {} ? true : false;
But when T
has a { isLoading: boolean }
property, Omit<{ isLoading: boolean } & T, 'isLoading'>
is not equal to T
(here Y
is false
):
type X<T> = Omit<{ isLoading: boolean } & T, 'isLoading'>;
type Y = X<{ isLoading: boolean }> extends { isLoading: boolean } ? true : false;
So for our use case, instead of assigning the Omit<{ isLoading: boolean } & T, 'isLoading'>
supertype to T
, we should assign the { isLoading: boolean } & T
subtype to T
:
function withLoading<T>(WrappedComponent: ComponentType<T>) {
return function (props: { isLoading: boolean } & T) {
return props.isLoading ? <p>Loading…</p> : <WrappedComponent {...props} />;
};
}