[react]: Remove deprecated+removed APIs (#20409)

* create-react-class: add definitions

* react-dom-factories: add definitions

* create-react-class: add tests, fix errors

* react-dom-factories: add tests, fix lint

* react: remove previously deprecated APIs

* Remove deprecated usages in other definitions

* redux-form: disable strictFunctionTypes

Changes to react typings revealed errors in redux-form that are present
in 'master'. This needs to be handled separately.

* Update create-react-class, react-dom-factories author

* Avoid importing create-react-class where possible

* Move top-level createReactClass tests to create-react-class
This commit is contained in:
John Gozde 2017-10-16 16:22:04 -06:00 committed by Andy
parent f5a5123320
commit bbf3e9cb0b
40 changed files with 449 additions and 295 deletions

View File

@ -0,0 +1,106 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import * as DOM from "react-dom-factories";
import * as createReactClass from "create-react-class";
interface Props {
foo: string;
}
interface State {
bar: number;
}
const props: Props & React.ClassAttributes<{}> = {
foo: "foo"
};
const container: Element = document.createElement("div");
//
// Top-Level API
// --------------------------------------------------------------------------
const ClassicComponent: React.ClassicComponentClass<Props> = createReactClass<Props, State>({
childContextTypes: {},
componentDidCatch(err, errorInfo) {
const msg: string = err.message;
const name: string = err.name;
const stack: string | undefined = err.stack;
const componentStack: string = errorInfo.componentStack;
},
componentDidMount() {},
componentDidUpdate(props, state) {
const foo: string = props.foo;
const bar: number = state.bar;
},
componentWillMount() {},
componentWillReceiveProps(nextProps) {
const oldFoo: string = nextProps.foo;
},
componentWillUnmount() {},
componentWillUpdate(props, state) {
const foo: string = props.foo;
const bar: number = state.bar;
},
contextTypes: {},
displayName: "Test",
getDefaultProps() {
return { foo: "f" };
},
getInitialState() {
return { bar: 1 };
},
mixins: [],
propTypes: {},
shouldComponentUpdate(this: React.ClassicComponent<Props, State>, nextProps, nextState) {
const newFoo: string = nextProps.foo;
const newBar: number = nextState.bar;
return newFoo !== this.props.foo && newBar !== this.state.bar;
},
statics: {
test: 1
},
reset() {
this.replaceState(this.getInitialState!());
},
render() {
return DOM.div(null,
DOM.input({
ref: input => this._input = input,
value: this.state.bar
}));
}
});
// React.createFactory
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);
// React.cloneElement
const clonedClassicElement: React.ClassicElement<Props> =
React.cloneElement(classicElement, props);
// ReactDOM.render
const classicComponent: React.ClassicComponent<Props> = ReactDOM.render(classicElement, container);
//
// React Components
// --------------------------------------------------------------------------
const displayName: string | undefined = ClassicComponent.displayName;
const defaultProps: Props = ClassicComponent.getDefaultProps ? ClassicComponent.getDefaultProps() : {} as Props;
const propTypes: React.ValidationMap<Props> | undefined = ClassicComponent.propTypes;
//
// Component API
// --------------------------------------------------------------------------
// classic
const isMounted: boolean = classicComponent.isMounted();
classicComponent.replaceState({ inputValue: "???", seconds: 60 });

13
types/create-react-class/index.d.ts vendored Normal file
View File

@ -0,0 +1,13 @@
// Type definitions for create-react-class 15.6
// Project: https://facebook.github.io/react/
// Definitions by: John Gozde <https://github.com/jgoz>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
import { ComponentSpec, ClassicComponentClass } from "react";
declare namespace createReactClass {}
declare function createReactClass<P, S>(spec: ComponentSpec<P, S>): ClassicComponentClass<P>;
export as namespace createReactClass;
export = createReactClass;

View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"jsx": "preserve"
},
"files": [
"index.d.ts",
"create-react-class-tests.ts"
]
}

View File

@ -0,0 +1,7 @@
{
"extends": "dtslint/dt.json",
"rules": {
"no-object-literal-type-assertion": false,
"no-unnecessary-generics": false
}
}

View File

@ -8,9 +8,9 @@ interface PersonProps {
age: number;
}
const Person: React.ClassicComponentClass<PersonProps> = React.createClass<PersonProps, {}>({
class Person extends React.Component<PersonProps> {
render(): React.ReactElement<any> { return null; }
});
}
const PersonTag = React.createFactory(Person);

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import { Component, PropTypes } from 'react';
import * as PropTypes from 'prop-types';
import { Component } from 'react';
import * as ReactDOM from 'react-dom';
import Pagination from 'material-ui-pagination';
import * as ui from 'material-ui';

View File

@ -1,9 +1,10 @@
import * as React from 'react';
import {
Component, ComponentClass, CSSProperties, PropTypes,
Component, ComponentClass, CSSProperties,
StatelessComponent, ReactElement, ReactInstance, ValidationMap
} from 'react';
import * as ReactDOM from 'react-dom';
import * as PropTypes from 'prop-types';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import { muiThemeable } from 'material-ui/styles/muiThemeable';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';

View File

@ -1,5 +1,6 @@
import * as angular from "angular";
import * as React from "react";
import * as PropTypes from "prop-types";
import { ReactDirective } from "ngreact";
const app = angular.module("app", ["react"]);
@ -24,13 +25,20 @@ app.directive('helloComponent', function(reactDirective: ReactDirective, $locati
return reactDirective(HelloComponent, undefined, {}, { $location });
});
var HelloComponent = React.createClass({
propTypes: {
fname : React.PropTypes.string.isRequired,
lname : React.PropTypes.string.isRequired
},
render: function() {
interface HelloProps {
fname: string;
lname: string;
}
class HelloComponent extends React.Component<HelloProps> {
static propTypes = {
fname : PropTypes.string.isRequired,
lname : PropTypes.string.isRequired
}
render() {
return <span>Hello {this.props.fname} {this.props.lname}</span>;
}
})
}
app.value('HelloComponent', HelloComponent);

View File

@ -29,7 +29,7 @@ class CalendarEvent {
}
// Basic Example Test
const BasicExample = React.createClass({
class BasicExample extends React.Component {
render() {
return (
<BigCalendar
@ -38,14 +38,14 @@ const BasicExample = React.createClass({
/>
);
}
});
}
ReactDOM.render(<BasicExample />, document.body);
const basicExampleHtml = ReactDOMServer.renderToString(<BasicExample />);
console.log('Test Results -> BasicExample', basicExampleHtml);
// Full API Example Test - based on API Documentation
// http://intljusticemission.github.io/react-big-calendar/examples/index.html#api
const FullAPIExample = React.createClass({
class FullAPIExample extends React.Component {
render() {
return (
<BigCalendar
@ -91,7 +91,7 @@ const FullAPIExample = React.createClass({
/>
);
}
});
}
ReactDOM.render(<FullAPIExample />, document.body);
const fullApiExampleHtml = ReactDOMServer.renderToString(<FullAPIExample />);
console.log('Test Results -> FullAPIExample', fullApiExampleHtml);

View File

@ -16,9 +16,7 @@ const data = {
]
};
export default React.createClass({
displayName: 'BarExample',
export default class BarExample extends React.Component {
render() {
return (
<div>
@ -34,4 +32,4 @@ export default React.createClass({
</div>
);
}
});
}

View File

@ -28,9 +28,7 @@ const data = {
]
};
export default React.createClass({
displayName: 'BubbleExample',
export default class BubbleExample extends React.Component {
render() {
return (
<div>
@ -39,4 +37,4 @@ export default React.createClass({
</div>
);
}
});
}

View File

@ -22,9 +22,7 @@ const data = {
}]
};
export default React.createClass({
displayName: 'DoughnutExample',
export default class DoughnutExample extends React.Component {
render() {
return (
<div>
@ -33,4 +31,4 @@ export default React.createClass({
</div>
);
}
});
}

View File

@ -16,9 +16,7 @@ const data = {
]
};
export default React.createClass({
displayName: 'BarExample',
export default class HorizontalBarExample extends React.Component {
render() {
return (
<div>
@ -27,4 +25,4 @@ export default React.createClass({
</div>
);
}
});
}

View File

@ -28,9 +28,7 @@ const data = {
]
};
export default React.createClass({
displayName: 'LineExample',
export default class LineExample extends React.Component {
render() {
return (
<div>
@ -39,4 +37,4 @@ export default React.createClass({
</div>
);
}
});
}

View File

@ -69,9 +69,7 @@ const options: ChartOptions = {
}
};
export default React.createClass({
displayName: 'MixExample',
export default class MixExample extends React.Component {
render() {
return (
<div>
@ -83,4 +81,4 @@ export default React.createClass({
</div>
);
}
});
}

View File

@ -22,9 +22,7 @@ const data = {
}]
};
export default React.createClass({
displayName: 'PieExample',
export default class PieExample extends React.Component {
render() {
return (
<div>
@ -33,4 +31,4 @@ export default React.createClass({
</div>
);
}
});
}

View File

@ -28,9 +28,7 @@ const data = {
]
};
export default React.createClass({
displayName: 'PolarExample',
export default class PolarExample extends React.Component {
render() {
return (
<div>
@ -39,4 +37,4 @@ export default React.createClass({
</div>
);
}
});
}

View File

@ -27,9 +27,7 @@ const data = {
]
};
export default React.createClass({
displayName: 'RadarExample',
export default class RadarExample extends React.Component {
render() {
return (
<div>
@ -38,4 +36,4 @@ export default React.createClass({
</div>
);
}
});
}

View File

@ -43,11 +43,10 @@ class Graph extends React.Component<any, any> {
});
const newDataSet = {
...oldDataSet
...oldDataSet,
data: newData
};
newDataSet.data = newData;
this.setState({ datasets: [newDataSet] });
}, 5000);
}
@ -59,9 +58,7 @@ class Graph extends React.Component<any, any> {
}
}
export default React.createClass({
displayName: 'RandomizedDataLineExample',
export default class RandomizedDataLineExample extends React.Component {
render() {
return (
<div>
@ -70,4 +67,4 @@ export default React.createClass({
</div>
);
}
});
}

View File

@ -2,9 +2,10 @@
// http://gaearon.github.io/react-dnd/docs-tutorial.html
import * as React from "react";
import * as DOM from "react-dom-factories";
import * as ReactDnd from "react-dnd";
const r = React.DOM;
const r = DOM;
import DragSource = ReactDnd.DragSource;
import DropTarget = ReactDnd.DropTarget;

View File

@ -2,9 +2,10 @@
// http://gaearon.github.io/react-dnd/docs-tutorial.html
import * as React from "react";
import * as DOM from "react-dom-factories";
import * as ReactDnd from "react-dnd";
var r = React.DOM;
var r = DOM;
import DragSource = ReactDnd.DragSource;
import DropTarget = ReactDnd.DropTarget;

12
types/react-dom-factories/index.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
// Type definitions for react-dom-factories 1.0
// Project: https://facebook.github.io/react/
// Definitions by: John Gozde <https://github.com/jgoz>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
export as namespace ReactDOMFactories;
export = ReactDOMFactories;
import { ReactDOM } from "react";
declare const ReactDOMFactories: ReactDOM;

View File

@ -0,0 +1,8 @@
import * as DOM from "react-dom-factories";
// tiny sampling of factories
DOM.a({}, "a");
DOM.div({},
DOM.span({}, DOM.b()),
DOM.ul({}, DOM.li({}, "test"))
);

View File

@ -0,0 +1,23 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"react-dom-factories-tests.ts"
]
}

View File

@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }

View File

@ -51,31 +51,32 @@ class Test4 extends React.Component {
}
}
var ListItem = React.createClass<{key: number; num: number;}, {}>({
render: function() {
class ListItem extends React.Component<{key: number; num: number}, {}> {
render() {
return <div className="infinite-list-item">
List Item {this.props.num}
</div>;
}
});
}
var InfiniteList = React.createClass({
getInitialState: function() {
return {
class InfiniteList extends React.Component<{}, {elements: React.ReactElement<any>[], isInfiniteLoading: boolean}> {
constructor(props?: {}, context?: any) {
super(props, context);
this.state = {
elements: this.buildElements(0, 20),
isInfiniteLoading: false
}
},
};
}
buildElements: function(start: number, end: number) {
buildElements(start: number, end: number) {
var elements = [] as React.ReactElement<any>[];
for (var i = start; i < end; i++) {
elements.push(<ListItem key={i} num={i}/>)
}
return elements;
},
}
handleInfiniteLoad: function() {
handleInfiniteLoad() {
var that = this;
this.setState({
isInfiniteLoading: true
@ -88,15 +89,15 @@ var InfiniteList = React.createClass({
elements: that.state.elements.concat(newElements)
});
}, 2500);
},
}
elementInfiniteLoad: function() {
elementInfiniteLoad() {
return <div className="infinite-list-item">
Loading...
</div>;
},
}
render: function() {
render() {
return <Infinite elementHeight={40}
containerHeight={250}
infiniteLoadBeginEdgeOffset={200}
@ -107,4 +108,4 @@ var InfiniteList = React.createClass({
{this.state.elements}
</Infinite>;
}
});
}

View File

@ -1,4 +1,4 @@
import { PropTypes } from 'react';
import * as PropTypes from 'prop-types';
import { deprecate, addIsDeprecated } from 'react-is-deprecated';
// test: one-off deprecation

View File

@ -1,7 +1,8 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as PropTypes from 'prop-types';
import * as L from 'leaflet';
import { Component, PropTypes } from 'react';
import { Component } from 'react';
import {
Children,
Circle,

View File

@ -28,8 +28,8 @@ import { Chip, ChipContact,
// all tests are from the examples provided here: https://tleunen.github.io/react-mdl/
// Badge tests
React.createClass({
render: function() {
class BadgeTests extends React.Component {
render() {
return (
<div>
{/* Number badge on icon */}
@ -41,7 +41,7 @@ React.createClass({
<Badge text="♥" overlap>
<Icon name="account_box" />
</Badge>
{/* Number badge on text */}
<Badge text="4">Inbox</Badge>
@ -50,11 +50,11 @@ React.createClass({
</div>
);
}
});
}
// Chip tests
React.createClass({
render: function() {
class ChipTests extends React.Component {
render() {
return (
<div>
<Chip>Basic chip</Chip>
@ -77,12 +77,12 @@ React.createClass({
</Chip>
</div>
);
}
});
}
}
// Button tests
React.createClass({
render: function() {
class ButtonTests extends React.Component {
render() {
return (
<div>
{/* Colored FAB button */}
@ -161,11 +161,11 @@ React.createClass({
</div>
);
}
})
}
// Card tests
React.createClass({
render: function() {
class CardTests extends React.Component {
render() {
return (
<div>
<Card shadow={0} style={{width: '512px', margin: 'auto'}}>
@ -181,7 +181,7 @@ React.createClass({
<IconButton name="share" />
</CardMenu>
</Card>
<Card shadow={0} style={{width: '320px', height: '320px', margin: 'auto'}}>
<CardTitle expand style={{color: '#fff', background: 'url(http://www.getmdl.io/assets/demos/dog.png) bottom right 15% no-repeat #46B6AC'}}>Update</CardTitle>
<CardText>
@ -192,7 +192,7 @@ React.createClass({
<Button colored>View Updates</Button>
</CardActions>
</Card>
<Card shadow={0} style={{width: '256px', height: '256px', background: 'url(http://www.getmdl.io/assets/demos/image_card.jpg) center / cover', margin: 'auto'}}>
<CardTitle expand />
<CardActions style={{height: '52px', padding: '16px', background: 'rgba(0,0,0,0.2)'}}>
@ -201,7 +201,7 @@ React.createClass({
</span>
</CardActions>
</Card>
<Card shadow={0} style={{width: '256px', height: '256px', background: '#3E4EB8'}}>
<CardTitle expand style={{alignItems: 'flex-start', color: '#fff'}}>
<h4 style={{marginTop: '0'}}>
@ -219,11 +219,11 @@ React.createClass({
</div>
);
}
});
}
// Checkbox tests
React.createClass({
render: function() {
class CheckboxTests extends React.Component {
render() {
return (
<div>
<Checkbox label="With ripple" ripple defaultChecked />
@ -232,11 +232,11 @@ React.createClass({
</div>
);
}
});
}
// DataTable tests
React.createClass({
render: function() {
class DataTableTests extends React.Component {
render() {
return (
<div>
<DataTable
@ -304,11 +304,14 @@ React.createClass({
</div>
);
}
});
}
// Dialog tests
React.createClass({
render: function() {
class DialogTests extends React.Component<{}, {openDialog: boolean}> {
handleOpenDialog() { }
handleCloseDialog() { }
render() {
return (
<div>
<div>
@ -324,7 +327,7 @@ React.createClass({
</DialogActions>
</Dialog>
</div>
<div>
<Button colored onClick={this.handleOpenDialog} raised ripple>Show Modal</Button>
<Dialog open={this.state.openDialog}>
@ -338,7 +341,7 @@ React.createClass({
</DialogActions>
</Dialog>
</div>
<div>
<Button colored onClick={this.handleOpenDialog} onAbort={this.handleCloseDialog} raised ripple>Show Dialog</Button>
<Dialog open={this.state.openDialog} onAbort={this.handleCloseDialog}>
@ -355,11 +358,11 @@ React.createClass({
</div>
);
}
});
}
// Grid tests
React.createClass({
render: function() {
class GridTests extends React.Component {
render() {
return (
<div>
<div style={{width: '80%', margin: 'auto'}}>
@ -396,11 +399,11 @@ React.createClass({
</div>
);
}
});
}
// IconToggle tests
React.createClass({
render: function() {
class IconToggleTests extends React.Component {
render() {
return (
<div>
<IconToggle ripple id="bold" name="format_bold" defaultChecked />
@ -409,11 +412,11 @@ React.createClass({
</div>
);
}
});
}
// Layout tests
React.createClass({
render: function() {
class LayoutTests extends React.Component<{}, {activeTab: number}> {
render() {
return (
<div>
{/* Uses a transparent header that draws on top of the layout's background */}
@ -602,7 +605,7 @@ React.createClass({
<Layout fixedHeader>
<Header>
<HeaderRow title="Title" />
<HeaderTabs activeTab={this.state.activeTab} onChange={(tabId) => this.setState({ activeTab: tabId })}>
<HeaderTabs activeTab={this.state.activeTab} onChange={(tabId) => {}}>
<Tab>Tab1</Tab>
<Tab>Tab2</Tab>
<Tab>Tab3</Tab>
@ -689,11 +692,11 @@ React.createClass({
</div>
);
}
});
}
// List tests
React.createClass({
render: function() {
class ListTests extends React.Component {
render() {
return (
<div>
<List>
@ -800,11 +803,11 @@ React.createClass({
</div>
);
}
});
}
// Menu tests
React.createClass({
render: function() {
class MenuTests extends React.Component {
render() {
return (
<div>
{/* Lower left */}
@ -853,11 +856,11 @@ React.createClass({
</div>
);
}
});
}
// ProgressBar tests
React.createClass({
render: function() {
class ProgressBarTests extends React.Component {
render() {
return (
<div>
{/* Simple Progress Bar */}
@ -871,11 +874,11 @@ React.createClass({
</div>
);
}
});
}
// Radio tests
React.createClass({
render: function() {
class RadioTests extends React.Component {
render() {
return (
<div>
<RadioGroup name="demo" value="opt1">
@ -890,11 +893,11 @@ React.createClass({
</div>
);
}
});
}
// Slider tests
React.createClass({
render: function() {
class SliderTests extends React.Component {
render() {
return (
<div>
{/* Default slider */}
@ -905,11 +908,15 @@ React.createClass({
</div>
);
}
});
}
// Snackbar tests
React.createClass({
render: function() {
class SnackbarTests extends React.Component {
handleClickActionSnackbar() {}
handleShowSnackbar() {}
handleTimeoutSnackbar() {}
render() {
return (
<div>
<div>
@ -920,7 +927,7 @@ React.createClass({
onTimeout={this.handleTimeoutSnackbar}
action="Undo">Button color changed.</Snackbar>
</div>
<div>
<Button raised onClick={this.handleShowSnackbar}>Show a Toast</Button>
<Snackbar
@ -932,11 +939,11 @@ React.createClass({
</div>
);
}
});
}
// Spinner tests
React.createClass({
render: function() {
class SpinnerTests extends React.Component {
render() {
return (
<div>
{/* Simple spinner */}
@ -947,11 +954,11 @@ React.createClass({
</div>
);
}
});
}
// Switch tests
React.createClass({
render: function() {
class SwitchTest extends React.Component {
render() {
return (
<div>
<Switch ripple id="switch1" defaultChecked>Ripple switch</Switch>
@ -960,11 +967,11 @@ React.createClass({
</div>
);
}
});
}
// Tab tests
React.createClass({
render: function() {
class TabTests extends React.Component<{}, {activeTab: number}> {
render() {
return (
<div>
<div className="demo-tabs">
@ -976,15 +983,15 @@ React.createClass({
<section>
<div className="content">Content for the tab: {this.state.activeTab}</div>
</section>
</div>
</div>
</div>
);
}
});
}
// Textfield tests
React.createClass({
render: function() {
class TextfieldTests extends React.Component {
render() {
return (
<div>
{/* Simple textfield */}
@ -1022,11 +1029,11 @@ React.createClass({
</div>
);
}
});
}
// Tooltip tests
React.createClass({
render: function() {
class TooltipTests extends React.Component {
render() {
return (
<div>
{/* Simple tooltip */}
@ -1071,15 +1078,15 @@ React.createClass({
</div>
);
}
});
}
// MDLComponent tests
React.createClass({
render: function() {
class MDLComponentTests extends React.Component {
render() {
return (
<MDLComponent recursive={false}>
<div />
</MDLComponent>
)
}
});
}

View File

@ -1,9 +1,10 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import { propTypes, defaultProps } from 'react-props-decorators';
@propTypes({
foo: React.PropTypes.string,
bar: React.PropTypes.number
foo: PropTypes.string,
bar: PropTypes.number
})
@defaultProps({
foo: "defaultString",

View File

@ -1,4 +1,5 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import {
RouterChildContext,
RouteComponentProps
@ -15,7 +16,7 @@ type Props = RouteComponentProps<Params>;
class ComponentThatUsesContext extends React.Component<Props> {
static contextTypes = {
router: React.PropTypes.object.isRequired
router: PropTypes.object.isRequired
};
context: RouterChildContext<Params>;
private onClick = () => {

View File

@ -1,4 +1,5 @@
import { PropTypes, PureComponent, Validator, Requireable } from 'react'
import { PureComponent, Validator, Requireable } from 'react'
import * as PropTypes from 'prop-types'
export type OnSectionRenderedParams = {
columnStartIndex: number,

View File

@ -1,4 +1,5 @@
import { PropTypes, PureComponent, Validator, Requireable } from 'react'
import { PureComponent, Validator, Requireable } from 'react'
import * as PropTypes from 'prop-types'
export type Dimensions = {
height: number,

View File

@ -167,8 +167,6 @@ declare namespace React {
// Top Level API
// ----------------------------------------------------------------------
function createClass<P, S>(spec: ComponentSpec<P, S>): ClassicComponentClass<P>;
// DOM Elements
function createFactory<T extends HTMLElement>(
type: keyof ReactHTML): HTMLFactory<T>;
@ -260,8 +258,6 @@ declare namespace React {
function isValidElement<P>(object: {}): object is ReactElement<P>;
const DOM: ReactDOM;
const PropTypes: ReactPropTypes;
const Children: ReactChildren;
const version: string;

View File

@ -10,6 +10,9 @@ import * as shallowCompare from "react-addons-shallow-compare";
import * as TestUtils from "react-addons-test-utils";
import * as TransitionGroup from "react-addons-transition-group";
import update = require("react-addons-update");
import * as createReactClass from "create-react-class";
import * as PropTypes from "prop-types";
import * as DOM from "react-dom-factories";
interface Props extends React.Attributes {
hello: string;
@ -47,46 +50,18 @@ const container: Element = document.createElement("div");
// Top-Level API
// --------------------------------------------------------------------------
const ClassicComponent: React.ClassicComponentClass<Props> =
React.createClass<Props, State>({
displayName: "ClassicComponent",
getDefaultProps() {
return {
hello: "hello",
world: "peace",
foo: 0,
};
},
getInitialState() {
return {
inputValue: this.context.someValue,
seconds: this.props.foo
};
},
reset() {
this.replaceState(this.getInitialState());
},
render() {
return React.DOM.div(null,
React.DOM.input({
ref: input => this._input = input,
value: this.state.inputValue
}));
}
});
class ModernComponent extends React.Component<Props, State>
implements MyComponent, React.ChildContextProvider<ChildContext> {
static propTypes: React.ValidationMap<Props> = {
foo: React.PropTypes.number
foo: PropTypes.number
};
static contextTypes: React.ValidationMap<Context> = {
someValue: React.PropTypes.string
someValue: PropTypes.string
};
static childContextTypes: React.ValidationMap<ChildContext> = {
someOtherValue: React.PropTypes.string
someOtherValue: PropTypes.string
};
context: Context;
@ -114,12 +89,12 @@ class ModernComponent extends React.Component<Props, State>
private _input: HTMLInputElement | null;
render() {
return React.DOM.div(null,
React.DOM.input({
return DOM.div(null,
DOM.input({
ref: input => this._input = input,
value: this.state.inputValue
}),
React.DOM.input({
DOM.input({
onChange: event => console.log(event.target)
}));
}
@ -131,8 +106,8 @@ class ModernComponent extends React.Component<Props, State>
class ModernComponentArrayRender extends React.Component<Props> {
render() {
return [React.DOM.h1({ key: "1" }, "1"),
React.DOM.h1({ key: "2" }, "2")];
return [DOM.h1({ key: "1" }, "1"),
DOM.h1({ key: "2" }, "2")];
}
}
@ -144,7 +119,7 @@ interface SCProps {
}
function StatelessComponent(props: SCProps) {
return props.foo ? React.DOM.div(null, props.foo) : null;
return props.foo ? DOM.div(null, props.foo) : null;
}
// tslint:disable-next-line:no-namespace
@ -155,7 +130,7 @@ namespace StatelessComponent {
const StatelessComponent2: React.SFC<SCProps> =
// props is contextually typed
props => React.DOM.div(null, props.foo);
props => DOM.div(null, props.foo);
StatelessComponent2.displayName = "StatelessComponent2";
StatelessComponent2.defaultProps = {
foo: 42
@ -164,7 +139,7 @@ StatelessComponent2.defaultProps = {
const StatelessComponent3: React.SFC<SCProps> =
// allows usage of props.children
// allows null return
props => props.foo ? React.DOM.div(null, props.foo, props.children) : null;
props => props.foo ? DOM.div(null, props.foo, props.children) : null;
// React.createFactory
const factory: React.CFactory<Props, ModernComponent> =
@ -177,11 +152,6 @@ const statelessFactory: React.SFCFactory<SCProps> =
const statelessFactoryElement: React.SFCElement<SCProps> =
statelessFactory(props);
const classicFactory: React.ClassicFactory<Props> =
React.createFactory(ClassicComponent);
const classicFactoryElement: React.ClassicElement<Props> =
classicFactory(props);
const domFactory: React.DOMFactory<React.DOMAttributes<{}>, Element> =
React.createFactory("div");
const domFactoryElement: React.DOMElement<React.DOMAttributes<{}>, Element> =
@ -191,7 +161,6 @@ const domFactoryElement: React.DOMElement<React.DOMAttributes<{}>, Element> =
const element: React.CElement<Props, ModernComponent> = React.createElement(ModernComponent, props);
const elementNoState: React.CElement<Props, ModernComponentNoState> = React.createElement(ModernComponentNoState, props);
const statelessElement: React.SFCElement<SCProps> = React.createElement(StatelessComponent, props);
const classicElement: React.ClassicElement<Props> = React.createElement(ClassicComponent, props);
const domElement: React.DOMElement<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> = React.createElement("div");
const htmlElement = React.createElement("input", { type: "text" });
const svgElement = React.createElement("svg", { accentHeight: 12 });
@ -226,8 +195,6 @@ const clonedStatelessElement: React.SFCElement<SCProps> =
// known problem: cloning with optional props don't work properly
// workaround: cast to actual props type
React.cloneElement(statelessElement, { foo: 44 } as SCProps);
const clonedClassicElement: React.ClassicElement<Props> =
React.cloneElement(classicElement, props);
// Clone base DOMElement
const clonedDOMElement: React.DOMElement<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> =
React.cloneElement(domElement, {
@ -251,7 +218,6 @@ const componentNullContainer: ModernComponent = ReactDOM.render(element, null);
const componentElementOrNull: ModernComponent = ReactDOM.render(element, document.getElementById("anelement"));
const componentNoState: ModernComponentNoState = ReactDOM.render(elementNoState, container);
const componentNoStateElementOrNull: ModernComponentNoState = ReactDOM.render(elementNoState, document.getElementById("anelement"));
const classicComponent: React.ClassicComponent<Props> = ReactDOM.render(classicElement, container);
const domComponent: Element = ReactDOM.render(domElement, container);
// Other Top-Level API
@ -271,14 +237,6 @@ const type: React.ComponentClass<Props> = element.type;
const elementProps: Props = element.props;
const key = element.key;
//
// React Components
// --------------------------------------------------------------------------
const displayName: string | undefined = ClassicComponent.displayName;
const defaultProps: Props = ClassicComponent.getDefaultProps ? ClassicComponent.getDefaultProps() : {} as Props;
const propTypes: React.ValidationMap<Props> | undefined = ClassicComponent.propTypes;
//
// Component API
// --------------------------------------------------------------------------
@ -288,10 +246,6 @@ const componentState: State = component.state;
component.setState({ inputValue: "!!!" });
component.forceUpdate();
// classic
const isMounted: boolean = classicComponent.isMounted();
classicComponent.replaceState({ inputValue: "???", seconds: 60 });
const myComponent = component as MyComponent;
myComponent.reset();
@ -315,18 +269,18 @@ RefComponent.create({ ref: c => componentRef = c });
componentRef.refMethod();
let domNodeRef: Element | null;
React.DOM.div({ ref: "domRef" });
DOM.div({ ref: "domRef" });
// type of node should be inferred
React.DOM.div({ ref: node => domNodeRef = node });
DOM.div({ ref: node => domNodeRef = node });
let inputNodeRef: HTMLInputElement | null;
React.DOM.input({ ref: node => inputNodeRef = node as HTMLInputElement });
DOM.input({ ref: node => inputNodeRef = node as HTMLInputElement });
//
// Attributes
// --------------------------------------------------------------------------
const children: any[] = ["Hello world", [null], React.DOM.span(null)];
const children: any[] = ["Hello world", [null], DOM.span(null)];
const divStyle: React.CSSProperties = { // CSSProperties
flex: "1 1 main-size",
backgroundImage: "url('hello.png')"
@ -353,15 +307,15 @@ const htmlAttr: React.HTMLProps<HTMLElement> = {
__html: "<strong>STRONG</strong>"
}
};
React.DOM.div(htmlAttr);
React.DOM.span(htmlAttr);
React.DOM.input(htmlAttr);
DOM.div(htmlAttr);
DOM.span(htmlAttr);
DOM.input(htmlAttr);
React.DOM.svg({
DOM.svg({
viewBox: "0 0 48 48",
xmlns: "http://www.w3.org/2000/svg"
},
React.DOM.rect({
DOM.rect({
className: 'foobar',
id: 'foo',
color: 'black',
@ -372,7 +326,7 @@ React.DOM.svg({
strokeDasharray: '30%',
strokeDashoffset: '20%'
}),
React.DOM.rect({
DOM.rect({
x: 10,
y: 22,
width: 28,
@ -380,7 +334,7 @@ React.DOM.svg({
strokeDasharray: 30,
strokeDashoffset: 20
}),
React.DOM.path({
DOM.path({
d: "M0,0V3H3V0ZM1,1V2H2V1Z",
fill: "#999999",
fillRule: "evenodd"
@ -388,34 +342,34 @@ React.DOM.svg({
);
//
// React.PropTypes
// PropTypes
// --------------------------------------------------------------------------
const PropTypesSpecification: React.ComponentSpec<any, any> = {
propTypes: {
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
optionalNode: React.PropTypes.node,
optionalElement: React.PropTypes.element,
optionalMessage: React.PropTypes.instanceOf(Date),
optionalEnum: React.PropTypes.oneOf(["News", "Photos"]),
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Date)
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalNode: PropTypes.node,
optionalElement: PropTypes.element,
optionalMessage: PropTypes.instanceOf(Date),
optionalEnum: PropTypes.oneOf(["News", "Photos"]),
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Date)
]),
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
requiredFunc: React.PropTypes.func.isRequired,
requiredAny: React.PropTypes.any.isRequired,
requiredFunc: PropTypes.func.isRequired,
requiredAny: PropTypes.any.isRequired,
customProp(props: any, propName: string, componentName: string): Error | null {
if (!/matchme/.test(props[propName])) {
return new Error("Validation failed!");
@ -424,7 +378,7 @@ const PropTypesSpecification: React.ComponentSpec<any, any> = {
},
// https://facebook.github.io/react/warnings/dont-call-proptypes.html#fixing-the-false-positive-in-third-party-proptypes
percentage: (object: any, key: string, componentName: string, ...rest: any[]): Error | null => {
const error = React.PropTypes.number(object, key, componentName, ...rest);
const error = PropTypes.number(object, key, componentName, ...rest);
if (error) {
return error;
}
@ -445,29 +399,29 @@ const PropTypesSpecification: React.ComponentSpec<any, any> = {
const ContextTypesSpecification: React.ComponentSpec<any, any> = {
contextTypes: {
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
optionalNode: React.PropTypes.node,
optionalElement: React.PropTypes.element,
optionalMessage: React.PropTypes.instanceOf(Date),
optionalEnum: React.PropTypes.oneOf(["News", "Photos"]),
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Date)
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalNode: PropTypes.node,
optionalElement: PropTypes.element,
optionalMessage: PropTypes.instanceOf(Date),
optionalEnum: PropTypes.oneOf(["News", "Photos"]),
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Date)
]),
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
requiredFunc: React.PropTypes.func.isRequired,
requiredAny: React.PropTypes.any.isRequired,
requiredFunc: PropTypes.func.isRequired,
requiredAny: PropTypes.any.isRequired,
customProp(props: any, propName: string, componentName: string): Error | null {
if (!/matchme/.test(props[propName])) {
return new Error("Validation failed!");
@ -488,7 +442,7 @@ const mappedChildrenArray: number[] =
React.Children.map<number>(children, (child) => 42);
React.Children.forEach(children, (child) => { });
const nChildren: number = React.Children.count(children);
let onlyChild: React.ReactElement<any> = React.Children.only(React.DOM.div()); // ok
let onlyChild: React.ReactElement<any> = React.Children.only(DOM.div()); // ok
onlyChild = React.Children.only([null, [[["Hallo"], true]], false]); // error
const childrenToArray: React.ReactChild[] = React.Children.toArray(children);
@ -516,7 +470,7 @@ class Timer extends React.Component<{}, TimerState> {
clearInterval(this._interval);
}
render() {
return React.DOM.div(
return DOM.div(
null,
"Seconds Elapsed: ",
this.state.secondsElapsed
@ -529,7 +483,7 @@ ReactDOM.render(React.createElement(Timer), container);
// createFragment addon
// --------------------------------------------------------------------------
createFragment({
a: React.DOM.div(),
a: DOM.div(),
b: ["a", false, React.createElement("span")]
});
@ -537,7 +491,7 @@ createFragment({
// CSSTransitionGroup addon
// --------------------------------------------------------------------------
React.createFactory(CSSTransitionGroup)({
component: React.createClass({
component: createReactClass({
render: (): null => null
}),
childFactory: (c) => c,
@ -563,7 +517,7 @@ React.createFactory(CSSTransitionGroup)({
//
// LinkedStateMixin addon
// --------------------------------------------------------------------------
React.createClass({
createReactClass({
mixins: [LinkedStateMixin],
getInitialState() {
return {
@ -572,12 +526,12 @@ React.createClass({
};
},
render() {
return React.DOM.div(null,
React.DOM.input({
return DOM.div(null,
DOM.input({
type: "checkbox",
checkedLink: this.linkState("isChecked")
}),
React.DOM.input({
DOM.input({
type: "text",
valueLink: this.linkState("message")
})
@ -616,9 +570,9 @@ Perf.printDOM();
//
// PureRenderMixin addon
// --------------------------------------------------------------------------
React.createClass({
createReactClass({
mixins: [PureRenderMixin],
render() { return React.DOM.div(null); }
render() { return DOM.div(null); }
});
//
@ -626,7 +580,7 @@ React.createClass({
// --------------------------------------------------------------------------
const inst: ModernComponent = TestUtils.renderIntoDocument<ModernComponent>(element);
const node: Element = TestUtils.renderIntoDocument(React.DOM.div());
const node: Element = TestUtils.renderIntoDocument(DOM.div());
TestUtils.Simulate.click(node);
TestUtils.Simulate.change(node);
@ -698,14 +652,14 @@ class SyntheticEventTargetValue extends React.Component<{}, { value: string }> {
this.state = { value: 'a' };
}
render() {
return React.DOM.textarea({
return DOM.textarea({
value: this.state.value,
onChange: e => this.setState({ value: e.target.value })
});
}
}
React.DOM.input({
DOM.input({
onChange: event => {
// `event.target` is guaranteed to be HTMLInputElement
event.target.value;

View File

@ -37,6 +37,8 @@ import libFormValueSelector from "redux-form/lib/formValueSelector";
import libReduxForm from "redux-form/lib/reduxForm";
import libActions from "redux-form/lib/actions";
// TODO: tests fail in TypeScript@next when strictFunctionTypes=true
/* Decorated components */
interface TestFormData {
foo: string;

View File

@ -37,4 +37,4 @@
"lib/selectors.d.ts",
"lib/SubmissionError.d.ts"
]
}
}

View File

@ -1,6 +1,7 @@
import * as React from 'react';
import { Component, PropTypes } from 'react';
import { Component } from 'react';
import * as PropTypes from 'prop-types';
import {createStore, combineReducers} from 'redux';
import {reduxForm, reducer as reduxFormReducer, ReduxFormProps} from 'redux-form';

View File

@ -3,6 +3,8 @@ import { Component } from 'react';
import { Action } from 'redux';
import { Field, GenericField, reduxForm, WrappedFieldProps, BaseFieldProps, FormProps, FormAction, actionTypes, reducer } from "redux-form";
// TODO: tests fail in TypeScript@next when strictFunctionTypes=true
interface CustomComponentProps {
customProp: string;
}
@ -86,7 +88,7 @@ reduxForm({
// adapted from: http://redux-form.com/6.0.0-alpha.4/examples/initializeFromState/
import { connect, DispatchProp } from 'react-redux'
const { DOM: { input } } = React
import { input } from 'react-dom-factories';
interface DataShape {
firstName: string;

View File

@ -31,4 +31,4 @@
"index.d.ts",
"redux-form-tests.tsx"
]
}
}