I am writing a partial function for react-alike functional components. It accepts a single parameter props
, then fill a specific key of the props. For example, the partial function foo
fills value of prop bar
to the new component.
function foo<T extends {bar: number}>(functionalComponent: (props: T) => JSX.Element) {
return (props: Omit<T, 'bar'>) => {
return functionalComponent({...props, bar: 3});
}
}
However, typescript compiler complains:
'Omit<T, "bar"> & { bar: number; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ bar: number; }'
The problem is very similar to this one, which uses infer
for a parameter list. However, I didn't find an object version, instead I found this github issue, which suggests using Omit
. However, Omit
does not work for the generic.
A tiny example to illustrate the problem:
function func<T extends {foo: number}>(param: Omit<T, 'foo'>): T {
return {...param, foo: 3};
}
'Omit<T, "foo"> & { foo: number; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ foo: number; }'
I also checked an answer that explains this error, but still can't get the point.
How can I make the partial function type signature work?
CodePudding user response:
Typescript can't follow what will happen with the Omit
as long as it still has an unresolved generic type parameter in it. What we could do to get this to type check is to add a union with Omit<T, 'bar'> & {bar: number}
to props
of functionalComponent
. While this seems the same as T
, it's inclusion will let typescript assign the wrapped component props to the functional component props. When T
is resolved, T
and Omit<T, 'bar'> & {bar: number}
will resolve to the same effective type, so it should have no impact to the call site:
type BaseProps ={bar: number}
function foo<T extends BaseProps>(functionalComponent: (props:
| T
| Omit<T, 'bar'> & BaseProps ) => JSX.Element) {
return (props: Omit<T, 'bar'>) => {
return functionalComponent({...props, bar: 3});
}
}
CodePudding user response:
I found a brute-force workaround: using the as
keyword. Not sure if there exists a better solution, so I'll leave it unresolved.
function func<T extends {foo: number}>(param: Omit<T, 'foo'>): T {
return {...param, foo: 3} as T;
}