0

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'],
};

see typescript playground

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[]

4
  • Your example effectively makes All['children'] equivalent to never, but component children have a lot more allowed types than your example here. Commented Jun 26, 2019 at 7:31
  • @PatrickRoberts Yes, React children have a lot more types, but I don’t find out why. if I define children: View[] in my Props and with React’s children definiion children?: ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;, according to my understanding, the final types should be View[] & ReactChild | View[] & ReactFragment | View[] & ReactPortal | View[] & boolean | View[] & null | View[] & undefined;. When I use View Array as children in my component, there’s no errror. I don’t see the difference between React children and my demo definition Commented Jun 26, 2019 at 7:44
  • Please provide a minimal reproducible example that someone can investigate in their own environment (or even better provide a link to a web IDE like codesandbox/stackblitz where you code is already set up) and then we can maybe tell you why your code is or is not working. Commented Jun 26, 2019 at 15:54
  • @jcalz thx for your replay. I find out, in React.Component children definition, type ReactFragment = {} | ReactNodeArray; which solve this problem Commented Jun 27, 2019 at 6:05

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

thx for your replay. I've updated my post. union types are easier to understand, but intersection types are not. Such as children definition in React.Component
0

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[] & {};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.