typescriptgenericscontravariance

How to specify a type guard for a function type with arguments without any in typescript?


Function types are contravariant for arguments and covariant for return types. How do i specify a generic function type with argument that extends Container type without using any in this case?

type Container<V> = {
  id: string;
  join: (value: V) => void;
};

const process = <V extends Container<unknown>>(processFn: (container: V) => boolean) => {
  // do something with processFn
}

type ExtendedContainer = Container<number> & { status: string; };
const processFn = (container: ExtendedContainer) => {
  return true;
}

process(processFn);

I understand why it errors. What i don't get is how i can express such a system without resorting to any in processFn type declaration for process? Or else, how can i make sure that the container argument extends type Container in general and get its type parameter?


Solution

  • I found a somewhat convoluted and ugly solution, using conditional types, that works:

    function process<C>(processFn: C extends Container<infer _> ? (value: C) => boolean : never) {
      // do something with processFn
    }
    
    process(processFn);
    
    process((a: string) => true); // Argument of type '(a: string) => true' is not assignable to parameter of type 'never'.(2345)
    

    Typescript playground