From 9e42df47b4ae305a061e2ee415f5fb2d3e9a436b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Gomes?= Date: Thu, 9 May 2019 13:11:52 +0100 Subject: [PATCH 1/6] Rewrite afterLayoutFlush as a generic TS function. It now takes a function and returns a cancelable function of the same type. This is a stricter contract that helps avoid typing errors in consumers of this library. --- .../after-layout-flush/{index.js => index.ts} | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) rename client/lib/after-layout-flush/{index.js => index.ts} (69%) diff --git a/client/lib/after-layout-flush/index.js b/client/lib/after-layout-flush/index.ts similarity index 69% rename from client/lib/after-layout-flush/index.js rename to client/lib/after-layout-flush/index.ts index b24dafd7ca216..d4fc5f4eb1f02 100644 --- a/client/lib/after-layout-flush/index.js +++ b/client/lib/after-layout-flush/index.ts @@ -1,4 +1,6 @@ -/** @format */ +interface Cancelable { + cancel: () => void; +} /** * Creates a delayed function that invokes `func` as soon as possible after the next layout @@ -12,18 +14,23 @@ * https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers * * @param {Function} func The function to be invoked after the layout flush - * @returns {Function} Returns the new delayed function + * @returns {Function} The new delayed function */ -export default function afterLayoutFlush( func ) { - let rafHandle = undefined; - let timeoutHandle = undefined; +export default function afterLayoutFlush< T extends ( ...args: any[] ) => any >( + func: T +): T & Cancelable { + // NodeJS and the browser have different types for timeouts (NodeJS.Timeout vs number), so + // we can't type this variable, or it will cause typing errors with `clearTimeout` later. + let timeoutHandle: any = undefined; + let rafHandle: number | undefined = undefined; const hasRAF = typeof requestAnimationFrame === 'function'; - let lastThis, lastArgs; + let lastThis: any; + let lastArgs: any[] | undefined; - const scheduleRAF = function( rafFunc ) { - return function( ...args ) { + const scheduleRAF = function( rafFunc: T ) { + return function( this: any, ...args: any[] ) { lastThis = this; lastArgs = args; @@ -37,11 +44,11 @@ export default function afterLayoutFlush( func ) { rafHandle = undefined; rafFunc(); } ); - }; + } as T; }; - const scheduleTimeout = function( timeoutFunc ) { - return function( ...args ) { + const scheduleTimeout = function( timeoutFunc: T ) { + return function( this: any, ...args: any[] ) { if ( ! hasRAF ) { lastThis = this; lastArgs = args; @@ -55,7 +62,7 @@ export default function afterLayoutFlush( func ) { } timeoutHandle = setTimeout( () => { - const callArgs = lastArgs; + const callArgs = lastArgs !== undefined ? lastArgs : []; const callThis = lastThis; lastArgs = undefined; @@ -65,17 +72,18 @@ export default function afterLayoutFlush( func ) { timeoutHandle = undefined; timeoutFunc.apply( callThis, callArgs ); }, 0 ); - }; + } as T; }; // if RAF is not supported (in Node.js test environment), the wrapped function // will only set a timeout. - let wrappedFunc = scheduleTimeout( func ); + let wrappedFunc: T = scheduleTimeout( func ); if ( hasRAF ) { wrappedFunc = scheduleRAF( wrappedFunc ); } - wrappedFunc.cancel = () => { + const wrappedWithCancel = wrappedFunc as T & Cancelable; + wrappedWithCancel.cancel = () => { lastThis = undefined; lastArgs = undefined; @@ -90,5 +98,5 @@ export default function afterLayoutFlush( func ) { } }; - return wrappedFunc; + return wrappedWithCancel; } From fb5e6a0289bf9c4022c8a576d656490d2f94af58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Gomes?= Date: Thu, 9 May 2019 16:27:53 +0100 Subject: [PATCH 2/6] Remove redundant (and incorrect) JSDoc types --- client/lib/after-layout-flush/index.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/client/lib/after-layout-flush/index.ts b/client/lib/after-layout-flush/index.ts index d4fc5f4eb1f02..eeac7edc02a5b 100644 --- a/client/lib/after-layout-flush/index.ts +++ b/client/lib/after-layout-flush/index.ts @@ -1,3 +1,5 @@ +/* eslint-disable valid-jsdoc */ + interface Cancelable { cancel: () => void; } @@ -13,8 +15,8 @@ interface Cancelable { * Inspired by the Firefox performance best practices MDN article at: * https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers * - * @param {Function} func The function to be invoked after the layout flush - * @returns {Function} The new delayed function + * @param func - The function to be invoked after the layout flush + * @returns The new delayed function */ export default function afterLayoutFlush< T extends ( ...args: any[] ) => any >( func: T @@ -100,3 +102,5 @@ export default function afterLayoutFlush< T extends ( ...args: any[] ) => any >( return wrappedWithCancel; } + +/* eslint-enable valid-jsdoc */ From 1ef3c3822620fa09472433addf04b71d2b1fe80f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Gomes?= Date: Thu, 9 May 2019 16:42:25 +0100 Subject: [PATCH 3/6] Remove redundant return type from function. --- client/lib/after-layout-flush/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/lib/after-layout-flush/index.ts b/client/lib/after-layout-flush/index.ts index eeac7edc02a5b..5c5041236750b 100644 --- a/client/lib/after-layout-flush/index.ts +++ b/client/lib/after-layout-flush/index.ts @@ -18,9 +18,7 @@ interface Cancelable { * @param func - The function to be invoked after the layout flush * @returns The new delayed function */ -export default function afterLayoutFlush< T extends ( ...args: any[] ) => any >( - func: T -): T & Cancelable { +export default function afterLayoutFlush< T extends ( ...args: any[] ) => any >( func: T ) { // NodeJS and the browser have different types for timeouts (NodeJS.Timeout vs number), so // we can't type this variable, or it will cause typing errors with `clearTimeout` later. let timeoutHandle: any = undefined; From b660050b5068b014b4001e7c9e7da194b242532f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Gomes?= Date: Thu, 9 May 2019 18:02:27 +0100 Subject: [PATCH 4/6] Set timeout handle type more explicitly --- client/lib/after-layout-flush/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/lib/after-layout-flush/index.ts b/client/lib/after-layout-flush/index.ts index 5c5041236750b..402ddfa59d703 100644 --- a/client/lib/after-layout-flush/index.ts +++ b/client/lib/after-layout-flush/index.ts @@ -4,6 +4,9 @@ interface Cancelable { cancel: () => void; } +// NodeJS and the browser have different return types for `setTimeout`. +type TimeoutHandle = ReturnType< typeof setTimeout >; + /** * Creates a delayed function that invokes `func` as soon as possible after the next layout * flush. At that time, it is very unlikely that the DOM has been written to since the last @@ -19,9 +22,7 @@ interface Cancelable { * @returns The new delayed function */ export default function afterLayoutFlush< T extends ( ...args: any[] ) => any >( func: T ) { - // NodeJS and the browser have different types for timeouts (NodeJS.Timeout vs number), so - // we can't type this variable, or it will cause typing errors with `clearTimeout` later. - let timeoutHandle: any = undefined; + let timeoutHandle: TimeoutHandle | undefined = undefined; let rafHandle: number | undefined = undefined; const hasRAF = typeof requestAnimationFrame === 'function'; From 166a47dc6a37919fbb518431504eb0acfbe0d67c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Gomes?= Date: Wed, 15 May 2019 09:49:40 -0600 Subject: [PATCH 5/6] Use global type for timer handle. --- client/lib/after-layout-flush/index.ts | 10 ++++++---- client/types.ts | 5 +++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/client/lib/after-layout-flush/index.ts b/client/lib/after-layout-flush/index.ts index 402ddfa59d703..8a25cf4ca18ac 100644 --- a/client/lib/after-layout-flush/index.ts +++ b/client/lib/after-layout-flush/index.ts @@ -1,12 +1,14 @@ /* eslint-disable valid-jsdoc */ +/** + * Internal dependencies + */ +import { TimerHandle } from 'types'; + interface Cancelable { cancel: () => void; } -// NodeJS and the browser have different return types for `setTimeout`. -type TimeoutHandle = ReturnType< typeof setTimeout >; - /** * Creates a delayed function that invokes `func` as soon as possible after the next layout * flush. At that time, it is very unlikely that the DOM has been written to since the last @@ -22,7 +24,7 @@ type TimeoutHandle = ReturnType< typeof setTimeout >; * @returns The new delayed function */ export default function afterLayoutFlush< T extends ( ...args: any[] ) => any >( func: T ) { - let timeoutHandle: TimeoutHandle | undefined = undefined; + let timeoutHandle: TimerHandle | undefined = undefined; let rafHandle: number | undefined = undefined; const hasRAF = typeof requestAnimationFrame === 'function'; diff --git a/client/types.ts b/client/types.ts index c0256e60fa165..2e9fb696d15a1 100644 --- a/client/types.ts +++ b/client/types.ts @@ -18,3 +18,8 @@ export type PostType = 'page' | 'post' | string; // Comment stuff export type CommentId = number; + +// Language stuff +export type Lazy< T > = () => T; +export type TimestampMS = ReturnType< typeof Date.now >; +export type TimerHandle = ReturnType< typeof setTimeout >; From 884ae27e4e7df51de4d189ec59c2288c6b64d539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Gomes?= Date: Wed, 15 May 2019 10:54:02 -0600 Subject: [PATCH 6/6] Remove ESLint disabling. --- client/lib/after-layout-flush/index.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/client/lib/after-layout-flush/index.ts b/client/lib/after-layout-flush/index.ts index 8a25cf4ca18ac..f7143c5e65a56 100644 --- a/client/lib/after-layout-flush/index.ts +++ b/client/lib/after-layout-flush/index.ts @@ -1,5 +1,3 @@ -/* eslint-disable valid-jsdoc */ - /** * Internal dependencies */ @@ -103,5 +101,3 @@ export default function afterLayoutFlush< T extends ( ...args: any[] ) => any >( return wrappedWithCancel; } - -/* eslint-enable valid-jsdoc */