Typescript: La intersección de dos parámetros genéricos para formar un tercero no se reconoce como equivalente

Creado en 13 ene. 2019  ·  3Comentarios  ·  Fuente: microsoft/TypeScript


Versión de TypeScript: 3.3.0-dev.201xxxxx


Términos de búsqueda:

Intersección de genéricos

Código

let connect = <R1,R2, R = R1&R2 >(mapState2Props: (state) => R1, mapDispatch2Props: (dispatch: any) => R2): R => {
  let state = {};
  let dispatch = () => { };
  return { ...mapState2Props(state), ...mapDispatch2Props(dispatch)}
}

Comportamiento esperado:
Esperaría que esto fuera válido porque he definido R = R1&R2 en la firma genérica.

Comportamiento real:

Obtiene un error Type 'R1 & R2' is not assignable to type 'R'. en la declaración de devolución. También probé R extends R1&R2 y obtengo el mismo error.

Enlace de patio de recreo:

Enlace

Asuntos relacionados:

https://github.com/Microsoft/TypeScript/issues/5823

Question

Comentario más útil

Creo que el error es correcto aquí. Sí, R1 & R2 se puede asignar al valor predeterminado de R , pero se puede crear una instancia de R con un tipo _más_ específico. Considere la siguiente instanciación.

connect<{ x: number; }, { y: number; }, { x: number, y: number, z: number }>( ... );

Esta es una instanciación válida de R1 , R2 y R , pero R1 & R2 es _no_ asignable a R porque falta el z parámetro.

En su ejemplo, el parámetro R no es realmente necesario (aunque su caso de uso real puede ser más complicado). Esto funciona:

let connect = <R1,R2>(mapState2Props: (state) => R1, mapDispatch2Props: (dispatch: any) => R2): R1 & R2 => {
  let state = {};
  let dispatch = () => { };
  return { ...mapState2Props(state), ...mapDispatch2Props(dispatch)}
}

Todos 3 comentarios

Creo que el error es correcto aquí. Sí, R1 & R2 se puede asignar al valor predeterminado de R , pero se puede crear una instancia de R con un tipo _más_ específico. Considere la siguiente instanciación.

connect<{ x: number; }, { y: number; }, { x: number, y: number, z: number }>( ... );

Esta es una instanciación válida de R1 , R2 y R , pero R1 & R2 es _no_ asignable a R porque falta el z parámetro.

En su ejemplo, el parámetro R no es realmente necesario (aunque su caso de uso real puede ser más complicado). Esto funciona:

let connect = <R1,R2>(mapState2Props: (state) => R1, mapDispatch2Props: (dispatch: any) => R2): R1 & R2 => {
  let state = {};
  let dispatch = () => { };
  return { ...mapState2Props(state), ...mapDispatch2Props(dispatch)}
}

hmm ya ese es un buen punto. El objetivo aquí era eventualmente llegar a donde podría simplemente especificar el tipo de retorno R y obtener seguridad de tipo que mapState2Props & mapDispatch2Props combinados daría como resultado un R válido

P.EJ:

interface IComponentProps{
  foo: string;
  doFoo: ()=>void
}
let props: IComponentProps = connect<IComponentProps>(
  (state) => { foo: state.foo },
  (dispatch) => {doFoo: () => dispatch('FOO')}
)

Sin embargo ... no estoy seguro de si eso es posible ... Parece que, en su lugar, necesitaría definir R1 y R2 como un subconjunto de R , pero dependen el uno del otro ...

Tenga en cuenta que R también podría ser un tipo completamente ajeno. Los argumentos de tipo predeterminado en genéricos no son restricciones.

connect<{ a: string }, { b: number }, { c: boolean[] }>(() => ({ a: "a" }), () => ({ b: 3 }))
¿Fue útil esta página
0 / 5 - 0 calificaciones