Typescript: Пересечение двух общих параметров с образованием третьего не признается эквивалентным

Созданный на 13 янв. 2019  ·  3Комментарии  ·  Источник: microsoft/TypeScript


Версия TypeScript: 3.3.0-dev.201xxxxx


Условия поиска:

Пересечение дженериков

Код

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

Ожидаемое поведение:
Я ожидал, что это будет действительным, потому что я определил R = R1&R2 в общей подписи.

Фактическое поведение:

Получить ошибку Type 'R1 & R2' is not assignable to type 'R'. в операторе возврата. Я также пробовал R extends R1&R2 и получаю ту же ошибку.

Ссылка на игровую площадку:

Ссылка

Связанные вопросы:

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

Question

Самый полезный комментарий

Я считаю, что здесь ошибка правильная. Да, R1 & R2 можно присвоить по умолчанию R , но R может быть создан с конкретным типом _more_. Рассмотрим следующий экземпляр.

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

Это действительный экземпляр R1 , R2 и R , но R1 & R2 _не_ присваивается R потому что в нем отсутствует z параметр.

В вашем примере параметр R самом деле не требуется (хотя ваш реальный вариант использования может быть более сложным). Это работает:

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

Все 3 Комментарий

Я считаю, что здесь ошибка правильная. Да, R1 & R2 можно присвоить по умолчанию R , но R может быть создан с конкретным типом _more_. Рассмотрим следующий экземпляр.

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

Это действительный экземпляр R1 , R2 и R , но R1 & R2 _не_ присваивается R потому что в нем отсутствует z параметр.

В вашем примере параметр R самом деле не требуется (хотя ваш реальный вариант использования может быть более сложным). Это работает:

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

хм, это хороший момент. Цель здесь заключалась в том, чтобы в конечном итоге добраться до того места, где вы могли бы просто указать тип возвращаемого значения R и получить безопасность типа, что mapState2Props & mapDispatch2Props сочетании приведет к действительному R Object.

НАПРИМЕР:

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

Однако ... я не уверен, возможно ли это вообще ... Похоже, вам нужно вместо этого определить R1 и R2 как некоторое подмножество R , но они зависят друг от друга ...

Обратите внимание, что R также может быть совершенно не связанным типом. Аргументы типа по умолчанию в универсальных шаблонах не являются ограничениями.

connect<{ a: string }, { b: number }, { c: boolean[] }>(() => ({ a: "a" }), () => ({ b: 3 }))
Была ли эта страница полезной?
0 / 5 - 0 рейтинги