Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 8 additions & 18 deletions types/create-react-class/create-react-class-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const container: Element = document.createElement("div");
// Top-Level API
// --------------------------------------------------------------------------

const ClassicComponent: React.ClassicComponentClass<Props> = createReactClass<Props, State>({
const ClassicComponent: createReactClass.ClassicComponentClass<Props> = createReactClass<Props, State>({
childContextTypes: {},
componentDidCatch(err, errorInfo) {
const msg: string = err.message;
Expand Down Expand Up @@ -53,7 +53,7 @@ const ClassicComponent: React.ClassicComponentClass<Props> = createReactClass<Pr
},
mixins: [],
propTypes: {},
shouldComponentUpdate(this: React.ClassicComponent<Props, State>, nextProps, nextState) {
shouldComponentUpdate(this: createReactClass.ClassicComponent<Props, State>, nextProps, nextState) {
const newFoo: string = nextProps.foo;
const newBar: number = nextState.bar;
return newFoo !== this.props.foo && newBar !== this.state.bar;
Expand All @@ -75,32 +75,20 @@ const ClassicComponent: React.ClassicComponentClass<Props> = createReactClass<Pr
},
});

const ClassicComponentNoProps: React.ClassicComponentClass = createReactClass({
const ClassicComponentNoProps: createReactClass.ClassicComponentClass = createReactClass({
render() {
return DOM.div();
},
});

const ClassicComponentNoState: React.ClassicComponentClass<{ text: string }> = createReactClass<{ text: string }>({
const ClassicComponentNoState: createReactClass.ClassicComponentClass<{ text: string }> = createReactClass<
{ text: string }
>({
render() {
return DOM.div(this.props.text);
},
});

// React.createFactory
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved all these tests to react and react-dom. They were actually testing that non-standard instance methods were preserved in these APIs which is unrelated to create-react-class.

const classicFactory: React.ClassicFactory<Props> = React.createFactory(ClassicComponent);
const classicFactoryElement: React.ClassicElement<Props> = classicFactory(props);

// React.createElement
const classicElement: React.ClassicElement<Props> = React.createElement(ClassicComponent, props);
const classicElementNullProps: React.ClassicElement<{}> = React.createElement(ClassicComponentNoProps, null);

// React.cloneElement
const clonedClassicElement: React.ClassicElement<Props> = React.cloneElement(classicElement, props);

// ReactDOM.render
const classicComponent: React.ClassicComponent<Props> = ReactDOM.render(classicElement, container);

//
// React Components
// --------------------------------------------------------------------------
Expand All @@ -113,6 +101,8 @@ const propTypes: React.ValidationMap<Props> | undefined = ClassicComponent.propT
// Component API
// --------------------------------------------------------------------------

const classicComponent = new ClassicComponent({ foo: "bar" });

// classic
const isMounted: boolean = classicComponent.isMounted();
classicComponent.replaceState({ inputValue: "???", seconds: 60 });
39 changes: 36 additions & 3 deletions types/create-react-class/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,40 @@
import { ClassicComponentClass, ComponentSpec } from "react";
import { Component, ComponentClass, ComponentLifecycle, ReactNode, ValidationMap } from "react";

declare namespace createReactClass {}
declare function createReactClass<P, S = {}>(spec: ComponentSpec<P, S>): ClassicComponentClass<P>;
declare namespace createReactClass {
interface Mixin<P, S> extends ComponentLifecycle<P, S> {
mixins?: Array<Mixin<P, S>> | undefined;
statics?: {
[key: string]: any;
} | undefined;

displayName?: string | undefined;
propTypes?: ValidationMap<any> | undefined;
contextTypes?: ValidationMap<any> | undefined;
childContextTypes?: ValidationMap<any> | undefined;

getDefaultProps?(): P;
getInitialState?(): S;
}

interface ComponentSpec<P, S> extends Mixin<P, S> {
render(): ReactNode;

[propertyName: string]: any;
}
interface ClassicComponent<P = {}, S = {}> extends Component<P, S> {
replaceState(nextState: S, callback?: () => void): void;
isMounted(): boolean;
getInitialState?(): S;
}

interface ClassicComponentClass<P = {}> extends Omit<ComponentClass<P>, "new"> {
new(props: P, context?: any): ClassicComponent<P, any>;
getDefaultProps?(): P;
}
}
declare function createReactClass<P, S = {}>(
spec: createReactClass.ComponentSpec<P, S>,
): createReactClass.ClassicComponentClass<P>;

export as namespace createReactClass;
export = createReactClass;
9 changes: 8 additions & 1 deletion types/react-dom/test/react-dom-tests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,21 @@ import * as ReactTestUtils from "react-dom/test-utils";
declare function describe(desc: string, f: () => void): void;
declare function it(desc: string, f: () => void): void;

class TestComponent extends React.Component<{ x: string }> {}
class TestComponent extends React.Component<{ x: string }> {
someInstanceMethod() {
return 42;
}
}

describe("ReactDOM", () => {
it("render", () => {
const rootElement = document.createElement("div");
ReactDOM.render(React.createElement("div"), rootElement);
ReactDOM.render(React.createElement("div"), document.createDocumentFragment());
ReactDOM.render(React.createElement("div"), document);

const instance = ReactDOM.render(React.createElement(TestComponent), rootElement);
instance.someInstanceMethod();
});

it("hydrate", () => {
Expand Down
17 changes: 9 additions & 8 deletions types/react/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ declare namespace React {
ref?: LegacyRef<T> | undefined;
}

/**
* @deprecated Use `ComponentElement<P, ClassicComponent<P, any>>` instead.
*/
type ClassicElement<P> = CElement<P, ClassicComponent<P, ComponentState>>;

// string fallback for custom web-components
Expand Down Expand Up @@ -269,9 +272,6 @@ declare namespace React {

// Custom components
function createFactory<P>(type: FunctionComponent<P>): FunctionComponentFactory<P>;
function createFactory<P>(
type: ClassType<P, ClassicComponent<P, ComponentState>, ClassicComponentClass<P>>,
): CFactory<P, ClassicComponent<P, ComponentState>>;
function createFactory<P, T extends Component<P, ComponentState>, C extends ComponentClass<P>>(
type: ClassType<P, T, C>,
): CFactory<P, T>;
Expand Down Expand Up @@ -307,11 +307,6 @@ declare namespace React {
props?: Attributes & P | null,
...children: ReactNode[]
): FunctionComponentElement<P>;
function createElement<P extends {}>(
type: ClassType<P, ClassicComponent<P, ComponentState>, ClassicComponentClass<P>>,
props?: ClassAttributes<ClassicComponent<P, ComponentState>> & P | null,
...children: ReactNode[]
): CElement<P, ClassicComponent<P, ComponentState>>;
function createElement<P extends {}, T extends Component<P, ComponentState>, C extends ComponentClass<P>>(
type: ClassType<P, T, C>,
props?: ClassAttributes<T> & P | null,
Expand Down Expand Up @@ -545,6 +540,9 @@ declare namespace React {

class PureComponent<P = {}, S = {}, SS = any> extends Component<P, S, SS> {}

/**
* @deprecated Use `ClassicComponent` from `create-react-class`
*/
interface ClassicComponent<P = {}, S = {}> extends Component<P, S> {
replaceState(nextState: S, callback?: () => void): void;
isMounted(): boolean;
Expand Down Expand Up @@ -612,6 +610,9 @@ declare namespace React {
displayName?: string | undefined;
}

/**
* @deprecated Use `ClassicComponentClass` from `create-react-class`
*/
interface ClassicComponentClass<P = {}> extends ComponentClass<P> {
new(props: P, context?: any): ClassicComponent<P, ComponentState>;
getDefaultProps?(): P;
Expand Down
11 changes: 11 additions & 0 deletions types/react/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,15 @@ const fragmentElementNullProps: React.ReactElement<{}> = React.createElement(Rea
React.createElement("div"),
React.createElement("div"),
]);
// $ExpectType CElement<{}, ComponentWithCustomInstanceMethods>
const myElement = React.createElement(
class ComponentWithCustomInstanceMethods extends React.Component {
customInstanceMethod = () => "Dave";
render() {
return null;
}
},
);

const customProps: React.HTMLProps<HTMLElement> = props;
const customDomElement = "my-element";
Expand All @@ -278,6 +287,8 @@ const clonedElement: React.CElement<Props, ModernComponent> = React.cloneElement

React.cloneElement(element, {});
React.cloneElement(element, {}, null);
// $ExpectType CElement<{}, ComponentWithCustomInstanceMethods>
React.cloneElement(myElement);

const clonedElement2: React.CElement<Props, ModernComponent> = React.cloneElement(element, {
ref: c => c && c.reset(),
Expand Down