Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Curry Predicate [duplicate]

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

like image 454
Ross Mackay Avatar asked Jan 29 '26 04:01

Ross Mackay


1 Answers

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.

like image 123
jcalz Avatar answered Jan 31 '26 21:01

jcalz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!