Skip to content

Commit

Permalink
Added a new type InfernoSingleNode to allow restricting children to any
Browse files Browse the repository at this point in the history
valid single child #1630
  • Loading branch information
Havunen committed Mar 25, 2023
1 parent c8551c4 commit a78124c
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 2 deletions.
104 changes: 103 additions & 1 deletion packages/inferno/__tests__/types.children.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component } from 'inferno';
import { Component, InfernoNode, InfernoSingleNode } from 'inferno';

describe('children types', () => {
it('Should be possible to type child as component', () => {
Expand Down Expand Up @@ -94,4 +94,106 @@ describe('children types', () => {
expect(valid1).toBeDefined();
expect(alsoValidForNow).toBeDefined();
});

it('Should be possible to type child as InfernoNode', () => {
interface ParentComponentProps {
children?: InfernoNode;
}

class FooBarCom extends Component<any, any> {
constructor(p, c) {
super(p, c);
}

public myMethod() {
return 'foobar';
}

public render({ children }) {
return <div>{children}</div>;
}
}

class ParentComponent extends Component<ParentComponentProps, any> {
constructor(p, c) {
super(p, c);
}
public render({ children }: ParentComponentProps) {
// children.myMethod();
// this.props.children.myMethod();
return <div>{children}</div>;
}
}

// InfernoNode accepts any valid JSX as children
const valid = (
<ParentComponent>
<FooBarCom />
<FooBarCom />
</ParentComponent>
);

// Children defined optional so leaving it empty is also ok
const valid2 = <ParentComponent></ParentComponent>;

// Single child also ok
const valid3 = <ParentComponent><FooBarCom /></ParentComponent>;

expect(valid).toBeDefined();
expect(valid2).toBeDefined();
expect(valid3).toBeDefined();
});

it('Should be possible to type child as InfernoNode', () => {
interface ParentComponentProps {
children: InfernoSingleNode;
}

class FooBarCom extends Component<any, any> {
constructor(p, c) {
super(p, c);
}

public myMethod() {
return 'foobar';
}

public render({ children }) {
return <div>{children}</div>;
}
}

class ParentComponent extends Component<ParentComponentProps, any> {
constructor(p, c) {
super(p, c);
}
public render({ children }: ParentComponentProps) {
// children.myMethod();
// this.props.children.myMethod();
return <div>{children}</div>;
}
}

// Children defined InfernoSingleNode so array is not acceptable
// @ts-expect-error
const invalid1 = <ParentComponent>
<FooBarCom />
<FooBarCom />
</ParentComponent>;

// Children not defined optional so leaving it empty is error
// @ts-expect-error
const invalid2 = <ParentComponent></ParentComponent>;

// Single child component is ok
const valid1 = <ParentComponent><FooBarCom /></ParentComponent>;

// Single child div is ok
const valid2 = <ParentComponent><div>1</div></ParentComponent>;

expect(invalid1).toBeDefined();
expect(invalid2).toBeDefined();
expect(valid1).toBeDefined();
expect(valid2).toBeDefined();
});
});
3 changes: 2 additions & 1 deletion packages/inferno/src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ type InfernoChild = Inferno.InfernoElement | InfernoText;
interface InfernoNodeArray extends Array<InfernoNode> {}

export type InfernoFragment = {} | InfernoNodeArray;
export type InfernoNode = InfernoChild | InfernoFragment | boolean | null | undefined;
export type InfernoSingleNode = InfernoChild | boolean | null | undefined;
export type InfernoNode = InfernoSingleNode | InfernoFragment;

// IComponent is defined here, instead of Component to de-couple implementation from interface
export interface IComponent<P, S> {
Expand Down

0 comments on commit a78124c

Please sign in to comment.