DefinitelyTyped/types/react-reconciler/index.d.ts
2019-01-09 16:02:31 -05:00

598 lines
22 KiB
TypeScript

// Type definitions for react-reconciler 0.18
// Project: https://reactjs.org/
// Definitions by: Nathan Bierema <https://github.com/Methuselah96>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
import { Component, ReactNode } from 'react';
declare function ReactReconciler<Type, Props, Container, Instance, TextInstance, HydratableInstance, PublicInstance, HostContext, UpdatePayload, ChildSet, TimeoutHandle, NoTimeout>(
// tslint:disable-next-line:no-unnecessary-generics
config: ReactReconciler.HostConfig<Type, Props, Container, Instance, TextInstance, HydratableInstance, PublicInstance, HostContext, UpdatePayload, ChildSet, TimeoutHandle, NoTimeout>,
): ReactReconciler.Reconciler<Instance, TextInstance, Container, PublicInstance>;
declare namespace ReactReconciler {
// react-reconciler/ReactFiber
// A Fiber is work on a Component that needs to be done or was done. There can
// be more than one per component.
interface Fiber {
// These first fields are conceptually members of an Instance. This used to
// be split into a separate type and intersected with the other Fiber fields,
// but until Flow fixes its intersection bugs, we've merged them into a
// single type.
// An Instance is shared between all versions of a component. We can easily
// break this out into a separate object to avoid copying so much to the
// alternate versions of the tree. We put this on a single object for now to
// minimize the number of objects created during the initial render.
// Tag identifying the type of fiber.
tag: WorkTag;
// Unique identifier of this child.
key: null | string;
// The value of element.type which is used to preserve the identity during
// reconciliation of this child.
elementType: any;
// The resolved function/class/ associated with this fiber.
type: any;
// The local state associated with this fiber.
stateNode: any;
// Conceptual aliases
// parent : Instance -> return The parent happens to be the same as the
// return fiber since we've merged the fiber and instance.
// Remaining fields belong to Fiber
// The Fiber to return to after finishing processing this one.
// This is effectively the parent, but there can be multiple parents (two)
// so this is only the parent of the thing we're currently processing.
// It is conceptually the same as the return address of a stack frame.
return: Fiber | null;
// Singly Linked List Tree Structure.
child: Fiber | null;
sibling: Fiber | null;
index: number;
// The ref last used to attach this node.
// I'll avoid adding an owner field for prod and model that as functions.
ref: null | (((handle: any) => void) & { _stringRef: string | null | undefined }) | RefObject;
// Input is the data coming into process this fiber. Arguments. Props.
pendingProps: any; // This type will be more specific once we overload the tag.
memoizedProps: any; // The props used to create the output.
// A queue of state updates and callbacks.
updateQueue: UpdateQueue<any> | null;
// The state used to create the output
memoizedState: any;
// A linked-list of contexts that this fiber depends on
firstContextDependency: ContextDependency<any> | null;
// Bitfield that describes properties about the fiber and its subtree. E.g.
// the ConcurrentMode flag indicates whether the subtree should be async-by-
// default. When a fiber is created, it inherits the mode of its
// parent. Additional flags can be set at creation time, but after that the
// value should remain unchanged throughout the fiber's lifetime, particularly
// before its child fibers are created.
mode: TypeOfMode;
// Effect
effectTag: SideEffectTag;
// Singly linked list fast path to the next fiber with side-effects.
nextEffect: Fiber | null;
// The first and last fiber with side-effect within this subtree. This allows
// us to reuse a slice of the linked list when we reuse the work done within
// this fiber.
firstEffect: Fiber | null;
lastEffect: Fiber | null;
// Represents a time in the future by which this work should be completed.
// Does not include work found in its subtree.
expirationTime: ExpirationTime;
// This is used to quickly determine if a subtree has no pending changes.
childExpirationTime: ExpirationTime;
// This is a pooled version of a Fiber. Every fiber that gets updated will
// eventually have a pair. There are cases when we can clean up pairs to save
// memory if we need to.
alternate: Fiber | null;
// Time spent rendering this Fiber and its descendants for the current update.
// This tells us how well the tree makes use of sCU for memoization.
// It is reset to 0 each time we render and only updated when we don't bailout.
// This field is only set when the enableProfilerTimer flag is enabled.
actualDuration?: number;
// If the Fiber is currently active in the "render" phase,
// This marks the time at which the work began.
// This field is only set when the enableProfilerTimer flag is enabled.
actualStartTime?: number;
// Duration of the most recent render time for this Fiber.
// This value is not updated when we bailout for memoization purposes.
// This field is only set when the enableProfilerTimer flag is enabled.
selfBaseDuration?: number;
// Sum of base times for all descedents of this Fiber.
// This value bubbles up during the "complete" phase.
// This field is only set when the enableProfilerTimer flag is enabled.
treeBaseDuration?: number;
// Conceptual aliases
// workInProgress : Fiber -> alternate The alternate used for reuse happens
// to be the same as work in progress.
// __DEV__ only
_debugID?: number;
_debugSource?: Source | null;
_debugOwner?: Fiber | null;
_debugIsCurrentlyTiming?: boolean;
}
// react-reconciler/ReactFiberExpirationTime
type ExpirationTime = number;
// react-reconciler/ReactFiberNewContext
interface ContextDependency<T> {
context: ReactContext<T>;
observedBits: number;
next: ContextDependency<any> | null;
}
// react-reconciler/ReactFiberReconciler
type OpaqueHandle = Fiber;
type OpaqueRoot = FiberRoot;
interface HostConfig<Type, Props, Container, Instance, TextInstance, HydratableInstance, PublicInstance, HostContext, UpdatePayload, ChildSet, TimeoutHandle, NoTimeout> {
getPublicInstance(instance: Instance | TextInstance): PublicInstance;
getRootHostContext(rootContainerInstance: Container): HostContext;
getChildHostContext(parentHostContext: HostContext, type: Type, rootContainerInstance: Container): HostContext;
prepareForCommit(containerInfo: Container): void;
resetAfterCommit(containerInfo: Container): void;
createInstance(
type: Type,
props: Props,
rootContainerInstance: Container,
hostContext: HostContext,
internalInstanceHandle: OpaqueHandle,
): Instance;
appendInitialChild(parentInstance: Instance, child: Instance | TextInstance): void;
finalizeInitialChildren(
parentInstance: Instance,
type: Type,
props: Props,
rootContainerInstance: Container,
hostContext: HostContext,
): boolean;
prepareUpdate(
instance: Instance,
type: Type,
oldProps: Props,
newProps: Props,
rootContainerInstance: Container,
hostContext: HostContext,
): null | UpdatePayload;
shouldSetTextContent(type: Type, props: Props): boolean;
shouldDeprioritizeSubtree(type: Type, props: Props): boolean;
createTextInstance(
text: string,
rootContainerInstance: Container,
hostContext: HostContext,
internalInstanceHandle: OpaqueHandle,
): TextInstance;
scheduleDeferredCallback(
callback: () => any,
options?: { timeout: number },
): any;
cancelDeferredCallback(callbackID: any): void;
setTimeout(handler: (...args: any[]) => void, timeout: number): TimeoutHandle | NoTimeout;
clearTimeout(handle: TimeoutHandle | NoTimeout): void;
noTimeout: NoTimeout;
now(): number;
// Temporary workaround for scenario where multiple renderers concurrently
// render using the same context objects. E.g. React DOM and React ART on the
// same page. DOM is the primary renderer; ART is the secondary renderer.
isPrimaryRenderer: boolean;
supportsMutation: boolean;
supportsPersistence: boolean;
supportsHydration: boolean;
// -------------------
// Mutation
// (optional)
// -------------------
appendChild?(parentInstance: Instance, child: Instance | TextInstance): void;
appendChildToContainer?(container: Container, child: Instance | TextInstance): void;
commitTextUpdate?(textInstance: TextInstance, oldText: string, newText: string): void;
commitMount?(
instance: Instance,
type: Type,
newProps: Props,
internalInstanceHandle: OpaqueHandle,
): void;
commitUpdate?(
instance: Instance,
updatePayload: UpdatePayload,
type: Type,
oldProps: Props,
newProps: Props,
internalInstanceHandle: OpaqueHandle,
): void;
insertBefore?(parentInstance: Instance, child: Instance | TextInstance, beforeChild: Instance | TextInstance): void;
insertInContainerBefore?(
container: Container,
child: Instance | TextInstance,
beforeChild: Instance | TextInstance,
): void;
removeChild?(parentInstance: Instance, child: Instance | TextInstance): void;
removeChildFromContainer?(container: Container, child: Instance | TextInstance): void;
resetTextContent?(instance: Instance): void;
// -------------------
// Persistence
// (optional)
// -------------------
cloneInstance?(
instance: Instance,
updatePayload: null | UpdatePayload,
type: Type,
oldProps: Props,
newProps: Props,
internalInstanceHandle: OpaqueHandle,
keepChildren: boolean,
recyclableInstance: Instance,
): Instance;
createContainerChildSet?(container: Container): ChildSet;
appendChildToContainerChildSet?(childSet: ChildSet, child: Instance | TextInstance): void;
finalizeContainerChildren?(container: Container, newChildren: ChildSet): void;
replaceContainerChildren?(container: Container, newChildren: ChildSet): void;
// -------------------
// Hydration
// (optional)
// -------------------
canHydrateInstance?(instance: HydratableInstance, type: Type, props: Props): null | Instance;
canHydrateTextInstance?(instance: HydratableInstance, text: string): null | TextInstance;
getNextHydratableSibling?(instance: Instance | TextInstance | HydratableInstance): null | HydratableInstance;
getFirstHydratableChild?(parentInstance: Instance | Container): null | HydratableInstance;
hydrateInstance?(
instance: Instance,
type: Type,
props: Props,
rootContainerInstance: Container,
hostContext: HostContext,
internalInstanceHandle: OpaqueHandle,
): null | UpdatePayload;
hydrateTextInstance?(
textInstance: TextInstance,
text: string,
internalInstanceHandle: OpaqueHandle,
): boolean;
didNotMatchHydratedContainerTextInstance?(
parentContainer: Container,
textInstance: TextInstance,
text: string,
): void;
didNotMatchHydratedTextInstance?(
parentType: Type,
parentProps: Props,
parentInstance: Instance,
textInstance: TextInstance,
text: string,
): void;
didNotHydrateContainerInstance?(parentContainer: Container, instance: Instance | TextInstance): void;
didNotHydrateInstance?(
parentType: Type,
parentProps: Props,
parentInstance: Instance,
instance: Instance | TextInstance,
): void;
didNotFindHydratableContainerInstance?(
parentContainer: Container,
type: Type,
props: Props,
): void;
didNotFindHydratableContainerTextInstance?(
parentContainer: Container,
text: string,
): void;
didNotFindHydratableInstance?(
parentType: Type,
parentProps: Props,
parentInstance: Instance,
type: Type,
props: Props,
): void;
didNotFindHydratableTextInstance?(
parentType: Type,
parentProps: Props,
parentInstance: Instance,
text: string,
): void;
}
// 0 is PROD, 1 is DEV.
// Might add PROFILE later.
type BundleType = 0 | 1;
interface DevToolsConfig<Instance, TextInstance> {
bundleType: BundleType;
version: string;
rendererPackageName: string;
// Note: this actually *does* depend on Fiber internal fields.
// Used by "inspect clicked DOM element" in React DevTools.
findFiberByHostInstance?: (instance: Instance | TextInstance) => Fiber;
// Used by RN in-app inspector.
// This API is unfortunately RN-specific.
// TODO: Change it to accept Fiber instead and type it properly.
getInspectorDataForViewTag?: (tag: number) => object;
}
interface Reconciler<Instance, TextInstance, Container, PublicInstance> {
updateContainerAtExpirationTime(
element: ReactNodeList,
container: OpaqueRoot,
parentComponent: Component<any, any> | null | undefined,
expirationTime: ExpirationTime,
callback: () => void | null | undefined,
): ExpirationTime;
createContainer(
containerInfo: Container,
isConcurrent: boolean,
hydrate: boolean,
): OpaqueRoot;
updateContainer(
element: ReactNodeList,
container: OpaqueRoot,
parentComponent: Component<any, any> | null | undefined,
callback: () => void | null | undefined,
): ExpirationTime;
flushRoot(root: OpaqueRoot, expirationTime: ExpirationTime): void;
requestWork(root: OpaqueRoot, expirationTime: ExpirationTime): void;
computeUniqueAsyncExpiration(): ExpirationTime;
batchedUpdates<A>(fn: () => A): A;
unbatchedUpdates<A>(fn: () => A): A;
deferredUpdates<A>(fn: () => A): A;
syncUpdates<A>(fn: () => A): A;
interactiveUpdates<A>(fn: () => A): A;
flushInteractiveUpdates(): void;
flushControlled(fn: () => any): void;
flushSync<A>(fn: () => A): A;
// Used to extract the return value from the initial render. Legacy API.
getPublicRootInstance(
container: OpaqueRoot,
): Component<any, any> | PublicInstance | null;
// Use for findDOMNode/findHostNode. Legacy API.
findHostInstance(component: object): PublicInstance | null;
// Used internally for filtering out portals. Legacy API.
findHostInstanceWithNoPortals(component: Fiber): PublicInstance | null;
injectIntoDevTools(devToolsConfig: DevToolsConfig<Instance, TextInstance>): boolean;
}
// react-reconciler/ReactFiberRoot
// TODO: This should be lifted into the renderer.
interface Batch {
_defer: boolean;
_expirationTime: ExpirationTime;
_onComplete: () => any;
_next: Batch | null;
}
type PendingInteractionMap = Map<ExpirationTime, Set<Interaction>>;
interface BaseFiberRootProperties {
// Any additional information from the host associated with this root.
containerInfo: any;
// Used only by persistent updates.
pendingChildren: any;
// The currently active root fiber. This is the mutable root of the tree.
current: Fiber;
// The following priority levels are used to distinguish between 1)
// uncommitted work, 2) uncommitted work that is suspended, and 3) uncommitted
// work that may be unsuspended. We choose not to track each individual
// pending level, trading granularity for performance.
//
// The earliest and latest priority levels that are suspended from committing.
earliestSuspendedTime: ExpirationTime;
latestSuspendedTime: ExpirationTime;
// The earliest and latest priority levels that are not known to be suspended.
earliestPendingTime: ExpirationTime;
latestPendingTime: ExpirationTime;
// The latest priority level that was pinged by a resolved promise and can
// be retried.
latestPingedTime: ExpirationTime;
pingCache:
| WeakMap<Thenable, Set<ExpirationTime>>
| Map<Thenable, Set<ExpirationTime>>
| null;
// If an error is thrown, and there are no more updates in the queue, we try
// rendering from the root one more time, synchronously, before handling
// the error.
didError: boolean;
pendingCommitExpirationTime: ExpirationTime;
// A finished work-in-progress HostRoot that's ready to be committed.
finishedWork: Fiber | null;
// Timeout handle returned by setTimeout. Used to cancel a pending timeout, if
// it's superseded by a new one.
timeoutHandle: any;
// Top context object, used by renderSubtreeIntoContainer
context: object | null;
pendingContext: object | null;
// Determines if we should attempt to hydrate on the initial mount
readonly hydrate: boolean;
// Remaining expiration time on this root.
// TODO: Lift this into the renderer
nextExpirationTimeToWorkOn: ExpirationTime;
expirationTime: ExpirationTime;
// List of top-level batches. This list indicates whether a commit should be
// deferred. Also contains completion callbacks.
// TODO: Lift this into the renderer
firstBatch: Batch | null;
// Linked-list of roots
nextScheduledRoot: FiberRoot | null;
}
// The following attributes are only used by interaction tracing builds.
// They enable interactions to be associated with their async work,
// And expose interaction metadata to the React DevTools Profiler plugin.
// Note that these attributes are only defined when the enableSchedulerTracing flag is enabled.
interface ProfilingOnlyFiberRootProperties {
interactionThreadID: number;
memoizedInteractions: Set<Interaction>;
pendingInteractionMap: PendingInteractionMap;
}
type FiberRoot = BaseFiberRootProperties & ProfilingOnlyFiberRootProperties;
// react-reconciler/ReactFiberScheduler
interface Thenable {
then(resolve: () => any, reject?: () => any): any;
}
// react-reconciler/ReactTypeOfMode
type TypeOfMode = number;
// react-reconciler/ReactUpdateQueue
interface Update<State> {
expirationTime: ExpirationTime;
tag: 0 | 1 | 2 | 3;
payload: any;
callback: (() => any) | null;
next: Update<State> | null;
nextEffect: Update<State> | null;
}
interface UpdateQueue<State> {
baseState: State;
firstUpdate: Update<State> | null;
lastUpdate: Update<State> | null;
firstCapturedUpdate: Update<State> | null;
lastCapturedUpdate: Update<State> | null;
firstEffect: Update<State> | null;
lastEffect: Update<State> | null;
firstCapturedEffect: Update<State> | null;
lastCapturedEffect: Update<State> | null;
}
// scheduler/Tracing
interface Interaction {
__count: number;
id: number;
name: string;
timestamp: number;
}
// shared/ReactElementType
interface Source {
fileName: string;
lineNumber: number;
}
// shared/ReactSideEffectTags
type SideEffectTag = number;
// shared/ReactTypes
type ReactEmpty = null | undefined | boolean;
type ReactNodeList = ReactEmpty | ReactNode;
interface ReactProviderType<T> {
$$typeof: symbol | number;
_context: ReactContext<T>;
}
interface ReactContext<T> {
$$typeof: symbol | number;
Consumer: ReactContext<T>;
Provider: ReactProviderType<T>;
unstable_read: () => T;
_calculateChangedBits: ((a: T, b: T) => number) | null;
_currentValue: T;
_currentValue2: T;
_threadCount: number;
// DEV only
_currentRenderer?: object | null;
_currentRenderer2?: object | null;
}
interface RefObject {
current: any;
}
// shared/ReactWorkTags
type WorkTag =
| 0
| 1
| 2
| 3
| 4
| 5
| 6
| 7
| 8
| 9
| 10
| 11
| 12
| 13
| 14
| 15
| 16
| 17
| 18;
}
export = ReactReconciler;