The compiler may not recognize that result.__times
will be defined before the arrow function in result
is executed. If you prefer to avoid altering the output JavaScript, consider using the non-null assertion operator !
to assert to the compiler that you know better and that result.__times
will indeed be defined:
export const wrapCountable = (func: Function): Function => {
let result: Function & { __times?: number } = () => {
result.__times!++ // Note the ! here
let value = null
try {
value = func()
} catch (e) {
throw e
}
return value
}
result.__times = 0
return result
}
This approach will suppress the error, although it is not entirely type-safe. You could remove the line result.__times = 0
and still suppress the error. Type assertions such as !
allow for potential deception of the compiler. Still, in this situation, an informed decision to use an assertion might be appropriate.
That said, a more concise version of your function could look like this:
const wrapCountable = <T>(func: () => T) => {
const result = Object.assign(() => {
result.__times++;
return func();
}, { __times: 0 });
return result;
}
const eighteen = wrapCountable(() => 18);
// const eighteen: (() => number) & {__times: number}
console.log(eighteen()); // 18
console.log(eighteen()); // 18
console.log(eighteen.__times); // 2
This version utilizes a generic T
to preserve the return value's type, employs Object.assign()
to prevent __times
from being undefined
, and eliminates the unnecessary try
/catch
block which seems redundant (as re-throwing the same exception is a no-op, correct?).
Hopefully, this explanation proves helpful. Best of luck!