[types-2.0] react - better strict mode compatibility (#11935)

* strict mode compatible

* include 11931

* vsiao - code review

* vsiao - code review - revert complex cloneelement case

* validator to accept null

* remove double tests

* test use Error | null

* code reviews

* code reviews
This commit is contained in:
Linken Dinh
2016-11-08 23:53:49 +09:00
committed by Masahiro Wakame
parent ded43c0126
commit 7f9ddef9b8
3 changed files with 38 additions and 33 deletions
+6 -6
View File
@@ -28,7 +28,7 @@ declare namespace React {
interface ReactElement<P> {
type: string | ComponentClass<P> | SFC<P>;
props: P;
key?: Key;
key: Key | null;
}
interface SFCElement<P> extends ReactElement<P> {
@@ -74,7 +74,7 @@ declare namespace React {
type ClassicFactory<P> = CFactory<P, ClassicComponent<P, ComponentState>>;
interface DOMFactory<P extends DOMAttributes<T>, T extends Element> {
(props?: P & ClassAttributes<T>, ...children: ReactNode[]): DOMElement<P, T>;
(props?: P & ClassAttributes<T> | null, ...children: ReactNode[]): DOMElement<P, T>;
}
interface HTMLFactory<T extends HTMLElement> extends DOMFactory<HTMLAttributes<T>, T> {
@@ -93,7 +93,7 @@ declare namespace React {
// Should be Array<ReactNode> but type aliases cannot be recursive
type ReactFragment = {} | Array<ReactChild | any[] | boolean>;
type ReactNode = ReactChild | ReactFragment | boolean;
type ReactNode = ReactChild | ReactFragment | boolean | null | undefined;
//
// Top Level API
@@ -201,7 +201,7 @@ declare namespace React {
type SFC<P> = StatelessComponent<P>;
interface StatelessComponent<P> {
(props: P, context?: any): ReactElement<any> | null;
(props: P, context?: any): ReactElement<any>;
propTypes?: ValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: P;
@@ -262,7 +262,7 @@ declare namespace React {
}
interface ComponentSpec<P, S> extends Mixin<P, S> {
render(): ReactElement<any>;
render(): ReactElement<any> | null;
[propertyName: string]: any;
}
@@ -2354,7 +2354,7 @@ declare namespace React {
// ----------------------------------------------------------------------
interface Validator<T> {
(object: T, key: string, componentName: string, ...rest: any[]): Error;
(object: T, key: string, componentName: string, ...rest: any[]): Error | null;
}
interface Requireable<T> extends Validator<T> {
+31 -26
View File
@@ -41,7 +41,7 @@ var props: Props & React.ClassAttributes<{}> = {
foo: 42
};
var container: Element;
var container: Element = document.createElement("div");
//
// Top-Level API
@@ -49,11 +49,12 @@ var container: Element;
var ClassicComponent: React.ClassicComponentClass<Props> =
React.createClass<Props, State>({
displayName: "ClassicComponent",
getDefaultProps() {
return {
hello: undefined,
hello: "hello",
world: "peace",
foo: undefined
foo: 0,
};
},
getInitialState() {
@@ -187,6 +188,10 @@ var domElement: React.ReactHTMLElement<HTMLDivElement> =
// React.cloneElement
var clonedElement: React.CElement<Props, ModernComponent> =
React.cloneElement(element, { foo: 43 });
React.cloneElement(element, {});
React.cloneElement(element, {}, null);
var clonedElement2: React.CElement<Props, ModernComponent> =
// known problem: cloning with key or ref requires cast
React.cloneElement(element, <React.ClassAttributes<ModernComponent>>{
@@ -240,18 +245,15 @@ domNode = ReactDOM.findDOMNode(domNode);
var type: React.ComponentClass<Props> = element.type;
var elementProps: Props = element.props;
var key: React.Key = element.key;
var t: React.ReactType;
var name = typeof t === "string" ? t : t.displayName;
var key = element.key;
//
// React Components
// --------------------------------------------------------------------------
var displayName: string = ClassicComponent.displayName;
var defaultProps: Props = ClassicComponent.getDefaultProps();
var propTypes: React.ValidationMap<Props> = ClassicComponent.propTypes;
var displayName: string | undefined = ClassicComponent.displayName;
var defaultProps: Props = ClassicComponent.getDefaultProps ? ClassicComponent.getDefaultProps() : <Props>{};
var propTypes: React.ValidationMap<Props> | undefined = ClassicComponent.propTypes;
//
// Component API
@@ -282,7 +284,7 @@ class RefComponent extends React.Component<RCProps, {}> {
}
}
var componentRef: RefComponent;
var componentRef: RefComponent = new RefComponent();
RefComponent.create({ ref: "componentRef" });
// type of c should be inferred
RefComponent.create({ ref: c => componentRef = c });
@@ -377,14 +379,14 @@ var PropTypesSpecification: React.ComponentSpec<any, any> = {
}),
requiredFunc: React.PropTypes.func.isRequired,
requiredAny: React.PropTypes.any.isRequired,
customProp: function(props: any, propName: string, componentName: string) {
customProp: function(props: any, propName: string, componentName: string): Error | null {
if (!/matchme/.test(props[propName])) {
return new Error("Validation failed!");
}
return null;
},
// 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 => {
percentage: (object: any, key: string, componentName: string, ...rest: any[]): Error | null => {
const error = React.PropTypes.number(object, key, componentName, ...rest);
if (error) {
return error;
@@ -395,7 +397,7 @@ var PropTypesSpecification: React.ComponentSpec<any, any> = {
return null;
}
},
render: (): React.ReactElement<any> => {
render: (): React.ReactElement<any> | null => {
return null;
}
};
@@ -429,14 +431,14 @@ var ContextTypesSpecification: React.ComponentSpec<any, any> = {
}),
requiredFunc: React.PropTypes.func.isRequired,
requiredAny: React.PropTypes.any.isRequired,
customProp: function(props: any, propName: string, componentName: string) {
customProp: function(props: any, propName: string, componentName: string): Error | null {
if (!/matchme/.test(props[propName])) {
return new Error("Validation failed!");
}
return null;
}
},
render: (): React.ReactElement<any> => {
render: (): null => {
return null;
}
};
@@ -499,7 +501,7 @@ createFragment({
// --------------------------------------------------------------------------
React.createFactory(CSSTransitionGroup)({
component: React.createClass({
render: (): React.ReactElement<any> => null
render: (): null => null
}),
childFactory: (c) => c,
transitionName: "transition",
@@ -605,16 +607,19 @@ var foundComponents: ModernComponent[] = TestUtils.scryRenderedComponentsWithTyp
// ReactTestUtils custom type guards
var emptyElement: React.ReactElement<{}>;
if (TestUtils.isElementOfType(emptyElement, StatelessComponent)) {
emptyElement.props.foo;
var emptyElement1: React.ReactElement<{}> = React.createElement(ModernComponent);
if (TestUtils.isElementOfType(emptyElement1, StatelessComponent)) {
emptyElement1.props.foo;
}
var emptyElement2: React.ReactElement<{}> = React.createElement(StatelessComponent);
if (TestUtils.isElementOfType(emptyElement2, StatelessComponent)) {
emptyElement2.props.foo;
}
var anyInstance: Element | React.Component<any, any>;
if (TestUtils.isDOMComponent(anyInstance)) {
anyInstance.getAttribute("className");
} else if (TestUtils.isCompositeComponent(anyInstance)) {
anyInstance.props;
if (TestUtils.isDOMComponent(container)) {
container.getAttribute("className");
} else if (TestUtils.isCompositeComponent(new ModernComponent())) {
new ModernComponent().props;
}
//
@@ -655,4 +660,4 @@ class ConstructorSpreadArgsPureComponent extends React.PureComponent<{}, {}> {
constructor(...args: any[]) {
super(...args);
}
}
}
+1 -1
View File
@@ -8,7 +8,7 @@
"module": "commonjs",
"target": "es6",
"noImplicitAny": true,
"strictNullChecks": false,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"