TypeScript Version: 3.3.0-dev.201xxxxx
Search Terms:
Intersection of generics
Code
let connect = <R1,R2, R = R1&R2 >(mapState2Props: (state) => R1, mapDispatch2Props: (dispatch: any) => R2): R => {
let state = {};
let dispatch = () => { };
return { ...mapState2Props(state), ...mapDispatch2Props(dispatch)}
}
Expected behavior:
I would expect that this would be valid because I have defined R = R1&R2
in the generic signature.
Actual behavior:
Get an error Type 'R1 & R2' is not assignable to type 'R'.
on the return statement. I've also tried R extends R1&R2
and I get the same error.
Playground Link:
Related Issues:
I believe the error is correct here. Yes R1 & R2
is assignable to the default of R
, but R
might be instantiated with a _more_ specific type. Consider the following instantiation.
connect<{ x: number; }, { y: number; }, { x: number, y: number, z: number }>( ... );
This is a valid instantiation of R1
, R2
, and R
, but R1 & R2
is _not_ assignable to R
because it is missing the z
parameter.
In your example the R
parameter is not actually required (though your real use-case may be more complicated). This works:
let connect = <R1,R2>(mapState2Props: (state) => R1, mapDispatch2Props: (dispatch: any) => R2): R1 & R2 => {
let state = {};
let dispatch = () => { };
return { ...mapState2Props(state), ...mapDispatch2Props(dispatch)}
}
hmm ya that's a good point. The goal here was to eventually get to where you could just specify the return type R
and get type safety that mapState2Props
& mapDispatch2Props
combined would result in a valid R
Object.
EG:
interface IComponentProps{
foo: string;
doFoo: ()=>void
}
let props: IComponentProps = connect<IComponentProps>(
(state) => { foo: state.foo },
(dispatch) => {doFoo: () => dispatch('FOO')}
)
However... I'm not sure if that is even possible... Seem like you would need to instead define R1 & R2 as some subset of R
, but they are dependent on each other...
Note that R
could also be a completely unrelated type. Default type arguments in generics are not constraints.
connect<{ a: string }, { b: number }, { c: boolean[] }>(() => ({ a: "a" }), () => ({ b: 3 }))
Most helpful comment
I believe the error is correct here. Yes
R1 & R2
is assignable to the default ofR
, butR
might be instantiated with a _more_ specific type. Consider the following instantiation.This is a valid instantiation of
R1
,R2
, andR
, butR1 & R2
is _not_ assignable toR
because it is missing thez
parameter.In your example the
R
parameter is not actually required (though your real use-case may be more complicated). This works: