Hey guys, I’m trying to use the <lodash/debounce> ...
# javascript
h
Hey guys, I’m trying to use the lodash/debounce function in my KotlinJS app. More information in thread 🙏
👀 1
✔️ 1
The import:
Copy code
@JsModule("lodash/debounce")
@JsNonModule
external fun <K, V> debounce(functionToDebounce: (K) -> V, debounceMillis: Int): (K) -> V
, and my test function
Copy code
debounce<Unit, Unit>({ console.log("debounced") }, 2000)
. The log statement never occurs. Thus I tried to change the
functionToDebounce
parameter- and the return value type to
dynamic
, and test without a lambda function as the first parameter:
Copy code
debounce<Unit, Unit>( console.log("debounced") , 2000)
, which triggers the runtime error
Copy code
Uncaught TypeError: Expected a function
    debounce Lodash
, indicating to me that the import is sort of correct(?). Lodash source code snippet:
Copy code
if (typeof func != 'function') {
    throw new TypeError(FUNC_ERROR_TEXT);
  }
Does anyone have a clue as to why my initial test function does not log to the console? 🙂
b
What's the js or ts function signature for debounce?
h
Copy code
* @since 0.1.0
 * @category Function
 * @param {Function} func The function to debounce.
 * @param {number} [wait=0]
 *  The number of milliseconds to delay; if omitted, `requestAnimationFrame` is
 *  used (if available).
 * @param {Object} [options={}] The options object.
 * @param {boolean} [options.leading=false]
 *  Specify invoking on the leading edge of the timeout.
 * @param {number} [options.maxWait]
 *  The maximum time `func` is allowed to be delayed before it's invoked.
 * @param {boolean} [options.trailing=true]
 *  Specify invoking on the trailing edge of the timeout.
 * @returns {Function} Returns the new debounced function.

function debounce(func, wait, options) {...}
Source: https://github.com/lodash/lodash/blob/master/debounce.js
b
Have a look at return doc. It returns a function that you need to invoke. i.e. it does not invoke your function for you
Try this kt signature:
Copy code
@JsModule("lodash/debounce")
@JsNonModule
external fun <K, V> debounce(functionToDebounce: (K) -> V, debounceMillis: Int, options: dynamic = definedExternally): (K) -> V
Copy code
debounce<Unit,Unit>({ console.log("debounced") }, 2000)()
h
Your intuition is indeed correct, well done! However, the suggested code does not compile:
Copy code
compileKotlinJs:
No value passed for parameter 'p1'
inside the final function invocation. It expects generic parameter “K”, even when it is defined as “Unit”. If I set the return value to
dynamic
it compiles and debounce works as expected. Thank you for you help! 🙌 Do you have some idea on how to tweak the return value / function invocation to prevent usage of
dynamic
return value?
b
Add a third generic maybe?
Copy code
@JsModule("lodash/debounce")
@JsNonModule
external fun <I, O, F: (I) -> O> debounce(functionToDebounce: F, debounceMillis: Int, options: dynamic = definedExternally): F
But to be honest this sounds like kotlin type inference bug
Alternatively, try invoking old signature like this (since your function takes
no
arguments as opposed to
no arguments of significance
)
Copy code
debounce<Nothing,Unit>({ console.log("debounced") }, 2000)()
r
Just in case you didn't consider it... you could use a Flow debounce instead and avoid calling the JS function entirely. https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/debounce.html
h
@Big Chungus both of your suggestions yield the same compile error. I agree it sounds like a type inference bug, I submitted an issue KT-52073. @rocketraman I did not, thanks for the suggestion! I might implement that as well and compare the two, although the lodash.debounce probably yields better JS performance, right?
r
You'll have to try it, but if you're not using coroutines elsewhere, I suspect it'll have a bigger impact on your bundle size than on runtime perf. But maybe you can get rid of lodash to compensate on the bundle size 🙂
h
Good thinking! I’m already using coroutines for my api calls, so I really should test it. Lodash was already in my node_modules before I started looking to use it, I guess some of the kotlin-wrappers I’m using already depends on lodash 🤗
t
1. Valid module name - with dot (from your url):
Copy code
@JsModule("lodash.debounce")