En el siguiente código, estoy tratando de entender cómo trabajar con tipos genéricos y de unión al volver a implementar algo similar a Either o Option.

type Error = {
  readonly _tag: 'error';
  status: number;
  statusText: string;
};

type Success<T> = {
  readonly _tag: 'success';
  response: T;
};

type PossibleError<T> = Error | Success<T>;

const isSuccessful = <T>(p: PossibleError<T>) => p._tag === 'success';

function fold<T>(
  onSuccess: (e: Success<T>) => void,
  onError: (a: Error) => void
): (pe: PossibleError<T>) => void {
  return pe => (isSuccessful(pe) ? onSuccess(pe.response) : onError(pe));
}

Pero recibo el siguiente error

error TS2339: Property 'response' does not exist on type 'PossibleError<T>'.
  Property 'response' does not exist on type 'Error'.

   return pe => (isSuccessful(pe) ? onSuccess(pe.response) : onError(pe));
                                                   ~~~~~~~~
error TS2345: Argument of type 'PossibleError<T>' is not assignable to parameter of type 'Error'.
  Type 'Success<T>' is missing the following properties from type 'Error': status, statusText

   return pe => (isSuccessful(pe) ? onSuccess(pe.response) : onError(pe));

Creo que el mecanografiado no puede determinar el tipo de pe en función de mi función isSuccessful. ¿Cómo obtengo las partes correctas de mi estructura de datos para poder hacer algo con ellas?

Miré la fp-ts implementación de cualquiera y pueden acceder a .left y .right, así que no estoy seguro de qué es diferente en mi código.

1
Jim Jeffries 28 jul. 2020 a las 11:19

1 respuesta

La mejor respuesta

¡Usted está cerca! Hay dos problemas:

  1. Necesita p is Success<T> en su función de protección de tipo

     const isSuccessful = <T>(p: PossibleError<T>): p is Success<T> => p._tag === 'success';
     // −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^
    
  2. Estás intentando pasar pe.response, no pe, a onSuccess, pero onSuccess está definido para tomar un Success<T>, no un T . Debe cambiar el tipo de onSuccess:

     function fold<T>(
       onSuccess: (e: T) => void,
     // −−−−−−−−−−−−−−^
       onError: (a: XError) => void
     ): (pe: PossibleError<T>) => void {
       return pe => (isSuccessful(pe) ? onSuccess(pe.response) : onError(pe));
     }
    

    Vínculo a la zona de juegos

    ... o páselo pe:

     function fold<T>(
       onSuccess: (e: Success<T>) => void,
       onError: (a: XError) => void
     ): (pe: PossibleError<T>) => void {
       return pe => (isSuccessful(pe) ? onSuccess(pe) : onError(pe));
     // −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^
     }
    

    Enlace al patio de juegos


Nota al margen: En esos, he cambiado Error a XError para que no entre en conflicto con la función Error estándar.

3
T.J. Crowder 28 jul. 2020 a las 08:28