I've some typescript
definitions like this:
interface T1 {
children: string[];
}
interface T2 {
children?: number | boolean | undefined | null;
}
type All = T1 & T2;
const b: All = {
children: ['test'],
};
I'm wondering what type exactly is the All['children']
property?
I can't assign string array
to it and don't know how I can use this intersection type
.
In real life, React.js
has a children
definition on React.Component
, when I define my own children
type, there is no error in this case.
UPDATE , add some real life code in React Native
code. I have the following definition:
interface Props {
children: View[];
}
export default Demo extends React.Component<Props> {
}
// later in parent component
<Demo>
<View></View>
<View></View>
</Demo>
I can't find out why typescript
can handle the children
for Demo
. this is the children
definition in React.Component
{
children?: ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
}
so, In my opinion, the final type
of children
in Demo
should be:
children: (View[] & ReactChild) | (View[] & ReactFragment) | (View[] & ReactPortal) | (View[] & boolean) | (View[] & null) | (View[] & undefined)
How can I pass View arrays
to Demo
as children.
UPDATE AGAIN , I find that, ReactFragment
definition is the key point.
type ReactFragment = {} | ReactNodeArray;
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
{}
in ReactFragment
, results in View[] & {}
, which is equivalent to View[]
An intersection type means that instances assignable to this type must be assignable to an constituent of the intersection. This leads the compiler to type children
as string[] & (number | boolean | undefined | null)
which is a very difficult type to realize and probably not what you are looking for anyway.
If you want All
to be either T1
or T2
then you must use a union:
interface T1 {
children: string[];
}
interface T2 {
children?: number | boolean | undefined | null;
}
type All = T1 | T2;
const b: All = { // OK
children: ['test'],
};
Or if you want some more complex merging logic, please provide more details.
It is something I missed when I read the React.ReactNode
definition. The definition is below:
type ReactText = string | number;
type ReactChild = ReactElement | ReactText;
interface ReactNodeArray extends Array<ReactNode> {}
type ReactFragment = {} | ReactNodeArray;
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
// children definition in React.Component, I’ve deleted other property definition
class Component<P, S> {
// React.Props<T> is now deprecated, which means that the `children`
// property is not available on `P` by default, even though you can
// always pass children as variadic arguments to `createElement`.
// In the future, if we can define its call signature conditionally
// on the existence of `children` in `P`, then we should remove this.
readonly props: Readonly<P> & Readonly<{ children?: ReactNode }>;
}
// my custom component Props definition
interface Props {
children: View[];
}
so, the children
definition for my component is:
type C = View[] & ReactNode;
// which is equivalent to this C2
type C2 = (View[] & ReactChild) | (View[] & ReactFragment) | (View[] & ReactPortal) | (View[] & boolean) | (View[] & null) | (View[] & undefined);
if we go deeper, and unfold the ReactFragment
, our type will be this
type C3 = (View[] & ReactChild) | (View[] & {}) | (View[] & ReactNodeArray) | (View[] & ReactPortal) | (View[] & boolean) | (View[] & null) | (View[] & undefined);
and what's the result of View[] & {}
. I've written a simple demo in typescript playground .
// Test is equivalent to View[]
type Test = View[] & {};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.