Example:
/* @flow */
type Props = {
title: string;
age: number;
};
type WrapProps = $Diff<Props, {
age: number;
}>;
const Person = (props: Props) => {};
const YoungPerson = (props: WrapProps) => {
return Person({age: 21, ...props});
};
14: return Person({age: 21, ...props});
^ object literal. Expected object instead of
14: return Person({age: 21, ...props});
^ Props
However if i declare WrapProps sub type manually, it works:
/* @flow */
type Props = {
title: string;
age: number;
};
/*type WrapProps = $Diff<Props, {
age: number;
}>;
*/
type WrapProps = {
title: string;
};
const Person = (props: Props) => {};
const YoungPerson = (props: WrapProps) => {
return Person({age: 21, ...props});
};
Seems like $Diff is not working correctly.
Indeed, you can't use the spread type on a $Diff type either:
type SpreadFromDiff = {...$Diff<Props, {title: string}>}
$Diff is not a public feature. It only works properly as lower bound, i.e. you can assign something to it, but can't use it after that
but the first example should work, right ?
i mean when using rest on the actual value that has been typed with $Diff
No, it shouldn't. $Diff only works properly as argument in declarations
@vkurchatkin it's publicly documented https://flow.org/en/docs/types/utilities/#toc-diff and I don't see how that example is different from the example in this issues (sans the ... spread).
It would be great if you can provide an example of how it can be used since I've tried $Diff multiple times without success and I'm afraid I don't follow any of the explanations above :(
$Diff aside, is there any other idiomatic way to annotate react components that wrap another component and exposing a subset of the wrapped component's props (i.e. providing the rest itself inside the wrapper)?
Edit
(Without declaring all the re-exposed props, which might be many and complex)
Here is as simple example:
type X = $Diff<{ a: string}, {}>;
var x: X = { a: 'string' }; // This works as expected
x.a; // This is an error
Each type consists of two parts: upper bound and lower bound. Upper bound defines if you can assign something to the type (i.e. if it's a subtype of the type). Lower bound defines if you can use the type in some particular way. $Diff only implements upper bound, so once you have something of type $Diff you can't do anything with it.
So if you want to use $Diff in your code you have to cast it to any. This is probably fine if you take $Diff as an argument, but not ideal if you return it from a function.
@vkurchatkin thanks for the example, that clears things up, really helpful!
Just a detail, in the other post above you wrote "lower bound" and this reply "upper bound" (which matches your explanation for $Diff)
Issue described by @vkurchatkin above doesn't seem to be an issue any longer since flow 0.57
Most helpful comment
Here is as simple example:
Each type consists of two parts: upper bound and lower bound. Upper bound defines if you can assign something to the type (i.e. if it's a subtype of the type). Lower bound defines if you can use the type in some particular way.
$Diffonly implements upper bound, so once you have something of type$Diffyou can't do anything with it.So if you want to use
$Diffin your code you have to cast it toany. This is probably fine if you take$Diffas an argument, but not ideal if you return it from a function.