I have a higher-order function (a react hook, but that doesn't really matter re the function signature) which takes an enum, and returns a function that checks if the value of the enum matches the provided one
When calling the function it doesn't properly narrow the types when used in a conditional, so that in the below example, status remains as SomeStatusEnum
// status: SomeStatusEnum
const didTransitionTo = useDidTransition(status);
if (didTransitionTo(SomeStatusEnum.SUCCESS)) {
// status is not narrowed to .SUCCESS here
}
The original implementation was this
/**
* A hook that given a value T, returns a predicate
* function which will return true when _entering_
* a matching state
*/
export function useDidTransition<S>(status: S) {
const prevStatus = usePreviousValue(status);
/**
* Did the status transition into `to`, from
* any other value at all
*/
function didTransitionTo(to: S): boolean {
return to !== prevStatus && to === status;
}
return didTransitionTo;
}
The below attempt at fixing it with a type guard gives the error Cannot find parameter 'status', as status is in the outer scope, not a param of didTransitionTo
export function useDidTransition<S>(status: S) {
const prevStatus = usePreviousValue(status);
function didTransitionTo<To extends S>(to: To): status is To {
return to !== prevStatus && to === status;
}
return didTransitionTo;
}
Edit: TS playground with attempted fix here
I'd rather just drop use of the function than make didTransitionTo take status as well
Unfortunately, it is not possible to curry functions that return a type predicate so that the predicate acts on a parameter of the outer scope. That is, you can't refactor (x: X, y: Y) => x is Z to (x: X) => (y: Y) => x is Z. Type predicates can only refer directly to one of the parameters directly in the signature (or this). See microsoft/TypeScript#16410 for more information.
You could uncurry your <S>(status: S) => <T extends S>(to: T) => status is T function to the form <S, T extends S>(status: S, to: T) => status is T. Or, as you said, you could drop the function entirely instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With