简体   繁体   中英

TypeScript intersection types

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

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM