[react] add forwardRef and createRef functions for React v16.3 (#24624)

* feat(react): add forwardRef and createRef functions

* fix(tests): fix failing tests
- datepicker needs to be updated to use optional generic types since it was using ClassAttributes incorrectly
This commit is contained in:
Ferdy Budhidharma 2018-04-10 12:22:57 -05:00 committed by Mohamed Hegazy
parent 5515e867df
commit 130f2eec2f
4 changed files with 33 additions and 5 deletions

View File

@ -11,7 +11,7 @@ interface State {
bar: number;
}
const props: Props & React.ClassAttributes<{}> = {
const props: Props = {
foo: "foo"
};

View File

@ -12,7 +12,7 @@ import * as momentRange from "moment-range";
export default class DateRangePicker extends React.Component<Props> { }
export as namespace ReactDateRangePicker;
export interface Props extends React.Props<{}> {
export interface Props<T = DateRangePicker> extends React.Props<T> {
bemBlock?: string;
bemNamespace?: string;
dateStates?: DateState[];
@ -57,7 +57,7 @@ export interface StateDefinition {
selectable?: boolean;
}
export interface PaginationArrowProps extends React.Props<{}> {
export interface PaginationArrowProps<T = PaginationArrow> extends React.Props<T> {
disabled?: boolean;
onTrigger?(): void;
direction?: 'next' | 'previous';

View File

@ -15,6 +15,7 @@
// Josh Rutherford <https://github.com/theruther4d>
// Guilherme Hübner <https://github.com/guilhermehubner>
// Josh Goldberg <https://github.com/joshuakgoldberg>
// Ferdy Budhidharma <https://github.com/ferdaber>
// Johann Rakotoharisoa <https://github.com/jrakotoharisoa>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.6
@ -79,7 +80,12 @@ declare namespace React {
type ComponentType<P = {}> = ComponentClass<P> | StatelessComponent<P>;
type Key = string | number;
type Ref<T> = string | { bivarianceHack(instance: T | null): any }["bivarianceHack"];
interface RefObject<T> {
readonly current: T | null;
}
type Ref<T> = string | { bivarianceHack(instance: T | null): any }["bivarianceHack"] | RefObject<T>;
// tslint:disable-next-line:interface-over-type-literal
type ComponentState = {};
@ -334,6 +340,14 @@ declare namespace React {
displayName?: string;
}
interface RefForwardingComponent<T, P = {}> {
(props: P & { children?: ReactNode }, ref?: Ref<T>): ReactElement<any> | null;
propTypes?: ValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
interface ComponentClass<P = {}> extends StaticLifecycle<P, any> {
new (props: P, context?: any): Component<P, ComponentState>;
propTypes?: ValidationMap<P>;
@ -535,6 +549,10 @@ declare namespace React {
[propertyName: string]: any;
}
function createRef<T>(): RefObject<T>;
function forwardRef<T, P = {}>(Component: RefForwardingComponent<T, P>): ComponentType<P & ClassAttributes<T>>;
//
// Event System
// ----------------------------------------------------------------------

View File

@ -37,7 +37,8 @@ interface MyComponent extends React.Component<Props, State> {
reset(): void;
}
const props: Props & React.ClassAttributes<{}> = {
// use any for ClassAttribute type sine we're using string refs
const props: Props & React.ClassAttributes<any> = {
key: 42,
ref: "myComponent42",
hello: "world",
@ -288,6 +289,15 @@ DOM.div({ ref: node => domNodeRef = node });
let inputNodeRef: HTMLInputElement | null;
DOM.input({ ref: node => inputNodeRef = node as HTMLInputElement });
const ForwardingRefComponent = React.forwardRef((props: {}, ref: React.Ref<RefComponent>) => {
return React.createElement(RefComponent, { ref });
});
function RefCarryingComponent() {
const ref: React.RefObject<RefComponent> = React.createRef();
return React.createElement(ForwardingRefComponent, { ref });
}
//
// Attributes
// --------------------------------------------------------------------------