Skip to content

Commit

Permalink
Use unknown instead of any when we explicitly don't know the type
Browse files Browse the repository at this point in the history
Also improve typings of options used in hooks
  • Loading branch information
andrewiggins committed Dec 13, 2023
1 parent 3d87a54 commit 85e3f71
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 50 deletions.
52 changes: 32 additions & 20 deletions hooks/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ let afterPaintEffects = [];
let EMPTY = [];

// Cast to use internal Options type
const options = /** @type {Options} */ (_options);
const options = /** @type {import('./internal').Options} */ (_options);

let oldBeforeDiff = options._diff;
let oldBeforeRender = options._render;
Expand All @@ -29,11 +29,13 @@ let oldBeforeUnmount = options.unmount;
const RAF_TIMEOUT = 100;
let prevRaf;

/** @type {(vnode: import('./internal').VNode) => void} */
options._diff = vnode => {
currentComponent = null;
if (oldBeforeDiff) oldBeforeDiff(vnode);
};

/** @type {(vnode: import('./internal').VNode) => void} */
options._render = vnode => {
if (oldBeforeRender) oldBeforeRender(vnode);

Expand Down Expand Up @@ -62,6 +64,7 @@ options._render = vnode => {
previousComponent = currentComponent;
};

/** @type {(vnode: import('./internal').VNode) => void} */
options.diffed = vnode => {
if (oldAfterDiff) oldAfterDiff(vnode);

Expand All @@ -82,6 +85,7 @@ options.diffed = vnode => {
previousComponent = currentComponent = null;
};

/** @type {(vnode: import('./internal').VNode) => void} */
options._commit = (vnode, commitQueue) => {
commitQueue.some(component => {
try {
Expand All @@ -101,6 +105,7 @@ options._commit = (vnode, commitQueue) => {
if (oldCommit) oldCommit(vnode, commitQueue);
};

/** @type {(vnode: import('./internal').VNode) => void} */
options.unmount = vnode => {
if (oldBeforeUnmount) oldBeforeUnmount(vnode);

Expand All @@ -127,11 +132,7 @@ options.unmount = vnode => {
*/
function getHookState(index, type) {
if (options._hook) {
options._hook(
/** @type {any} */ (currentComponent),
index,
currentHook || type
);
options._hook(currentComponent, index, currentHook || type);
}
currentHook = 0;

Expand All @@ -155,18 +156,21 @@ function getHookState(index, type) {
}

/**
* @param {import('./index').StateUpdater<any>} [initialState]
* @template {unknown} S
* @param {import('./index').StateUpdater<S>} [initialState]
*/
export function useState(initialState) {
currentHook = 1;
return useReducer(invokeOrReturn, initialState);
}

/**
* @param {import('./index').Reducer<any, any>} reducer
* @param {import('./index').StateUpdater<any>} initialState
* @template {unknown} S
* @template {unknown} A
* @param {import('./index').Reducer<S, A>} reducer
* @param {import('./index').StateUpdater<S>} initialState
* @param {(initialState: any) => void} [init]
* @returns {[ any, (state: any) => void ]}
* @returns {[ S, (state: S) => void ]}
*/
export function useReducer(reducer, initialState, init) {
/** @type {import('./internal').ReducerHookState} */
Expand Down Expand Up @@ -268,7 +272,7 @@ export function useReducer(reducer, initialState, init) {

/**
* @param {import('./internal').Effect} callback
* @param {any[]} args
* @param {unknown[]} args
*/
export function useEffect(callback, args) {
/** @type {import('./internal').EffectHookState} */
Expand All @@ -283,7 +287,7 @@ export function useEffect(callback, args) {

/**
* @param {import('./internal').Effect} callback
* @param {any[]} args
* @param {unknown[]} args
*/
export function useLayoutEffect(callback, args) {
/** @type {import('./internal').EffectHookState} */
Expand All @@ -296,6 +300,7 @@ export function useLayoutEffect(callback, args) {
}
}

/** @type {(initialValue: unknown) => unknown} */
export function useRef(initialValue) {
currentHook = 5;
return useMemo(() => ({ current: initialValue }), []);
Expand All @@ -304,7 +309,7 @@ export function useRef(initialValue) {
/**
* @param {object} ref
* @param {() => object} createHandle
* @param {any[]} args
* @param {unknown[]} args
*/
export function useImperativeHandle(ref, createHandle, args) {
currentHook = 6;
Expand All @@ -323,8 +328,8 @@ export function useImperativeHandle(ref, createHandle, args) {
}

/**
* @param {() => any} factory
* @param {any[]} args
* @param {() => unknown} factory
* @param {unknown[]} args
*/
export function useMemo(factory, args) {
/** @type {import('./internal').MemoHookState} */
Expand All @@ -341,7 +346,7 @@ export function useMemo(factory, args) {

/**
* @param {() => void} callback
* @param {any[]} args
* @param {unknown[]} args
*/
export function useCallback(callback, args) {
currentHook = 8;
Expand Down Expand Up @@ -384,7 +389,7 @@ export function useDebugValue(value, formatter) {
}

/**
* @param {(error: any, errorInfo: import('preact').ErrorInfo) => void} cb
* @param {(error: unknown, errorInfo: import('preact').ErrorInfo) => void} cb
*/
export function useErrorBoundary(cb) {
/** @type {import('./internal').ErrorBoundaryHookState} */
Expand All @@ -405,6 +410,7 @@ export function useErrorBoundary(cb) {
];
}

/** @type {() => string} */
export function useId() {
/** @type {import('./internal').IdHookState} */
const state = getHookState(currentIndex++, 11);
Expand Down Expand Up @@ -482,7 +488,7 @@ function afterPaint(newQueueLength) {
}

/**
* @param {import('./internal').EffectHookState} hook
* @param {import('./internal').HookState} hook
*/
function invokeCleanup(hook) {
// A hook cleanup can introduce a call to render which creates a new root, this will call options.vnode
Expand Down Expand Up @@ -510,8 +516,8 @@ function invokeEffect(hook) {
}

/**
* @param {any[]} oldArgs
* @param {any[]} newArgs
* @param {unknown[]} oldArgs
* @param {unknown[]} newArgs
*/
function argsChanged(oldArgs, newArgs) {
return (
Expand All @@ -521,6 +527,12 @@ function argsChanged(oldArgs, newArgs) {
);
}

/**
* @template Arg
* @param {Arg} arg
* @param {(arg: Arg) => any} f
* @returns {any}
*/
function invokeOrReturn(arg, f) {
return typeof f == 'function' ? f(arg) : f;
}
60 changes: 30 additions & 30 deletions hooks/src/internal.d.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
import { Reducer } from '.';
import { Reducer, StateUpdater } from '.';

export { PreactContext };

/**
* The type of arguments passed to a Hook function. While this type is not
* strictly necessary, they are given a type name to make it easier to read
* the following types and trace the flow of data.
*/
export type HookArgs = any;

/**
* The return type of a Hook function. While this type is not
* strictly necessary, they are given a type name to make it easier to read
* the following types and trace the flow of data.
*/
export type HookReturnValue = any;

/** The public function a user invokes to use a Hook */
export type Hook = (...args: HookArgs[]) => HookReturnValue;
export interface Options extends globalThis.Options {
/** Attach a hook that is invoked before a vnode is diffed. */
_diff?(vnode: VNode): void;
diffed?(vnode: VNode): void;
/** Attach a hook that is invoked before a vnode has rendered. */
_render?(vnode: VNode): void;
/** Attach a hook that is invoked after a tree was mounted or was updated. */
_commit?(vnode: VNode, commitQueue: Component[]): void;
_unmount?(vnode: VNode): void;
/** Attach a hook that is invoked before a hook's state is queried. */
_hook?(component: Component, index: number, type: HookType): void;
}

// Hook tracking

Expand All @@ -37,6 +33,7 @@ export interface Component extends globalThis.Component<any, any> {

export interface VNode extends globalThis.VNode {
_mask?: [number, number];
_component?: Component; // Override with our specific Component type
}

export type HookState =
Expand All @@ -49,35 +46,38 @@ export type HookState =

interface BaseHookState {
_value?: unknown;
_component?: undefined;
_nextValue?: undefined;
_pendingValue?: undefined;
_args?: undefined;
_pendingArgs?: undefined;
_component?: undefined;
_cleanup?: undefined;
}

export type Effect = () => void | Cleanup;
export type Cleanup = () => void;

export interface EffectHookState extends BaseHookState {
_value?: Effect;
_args?: any[];
_pendingArgs?: any[];
_args?: unknown[];
_pendingArgs?: unknown[];
_cleanup?: Cleanup | void;
}

export interface MemoHookState extends BaseHookState {
_value?: any;
_pendingValue?: any;
_args?: any[];
_pendingArgs?: any[];
_factory?: () => any;
_value?: unknown;
_pendingValue?: unknown;
_args?: unknown[];
_pendingArgs?: unknown[];
_factory?: () => unknown;
}

export interface ReducerHookState extends BaseHookState {
_nextValue?: any;
_value?: any;
export interface ReducerHookState<S = unknown, A = unknown>
extends BaseHookState {
_nextValue?: [S, StateUpdater<S>];
_value?: [S, StateUpdater<S>];
_component?: Component;
_reducer?: Reducer<any, any>;
_reducer?: Reducer<S, A>;
}

export interface ContextHookState extends BaseHookState {
Expand All @@ -87,7 +87,7 @@ export interface ContextHookState extends BaseHookState {
}

export interface ErrorBoundaryHookState extends BaseHookState {
_value?: (error: any, errorInfo: ErrorInfo) => void;
_value?: (error: unknown, errorInfo: ErrorInfo) => void;
}

export interface IdHookState extends BaseHookState {
Expand Down

0 comments on commit 85e3f71

Please sign in to comment.