Definitelytyped: Проблема с connect() в @types/react-redux, появившаяся в 4.4.41.

Созданный на 6 июн. 2017  ·  44Комментарии  ·  Источник: DefinitelyTyped/DefinitelyTyped

Используя @types/react-redux версии 4.4.40, следующий код

import * as React from 'react';
import {connect} from "react-redux";

interface State {
    y: number;
}

// Own properties
interface OP {
    x: number;
}

// State properties
interface SP {
    y: number;
}

function mapStateToProps(state: State, ownProps: OP): OP & SP {
    return {
        x: ownProps.x,
        y: state.y,
    };
}

class TestComp extends React.Component<OP & SP, null> {
    render() {
        return <p>Hello</p>;
    }
}

export default connect(mapStateToProps)(TestComp);

позволит мне использовать TestComp следующим образом:

const tc = <TestComp x={42}/>;

В версиях 4.4.41 и 4.4.42 приведенное выше приводит к следующей ошибке компиляции:

error TS2324: Property 'y' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<OP & SP, ComponentState>> & { children?:...'.

/cc @thasner @seansfkelley @tkqubo @blakeembrey @sandersn @mhegazy @andy-ms @hans-permana

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

Снова ломается в Typescript 3.0.1. Привет Тиен!

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

Я также получаю эту ошибку. Похоже, что один из typedef случайно поменял местами TOwnProps и TMergedProps / TStateProps , но я лишь бегло взглянул на index.d.ts .

Есть новости по этому вопросу? Я думаю, что это может быть показательным для нового разработчика, переходящего на redux + typescript, спасибо за отличную работу.

@brauliodiez Я объединил исправление @blakeembrey #16969. Он должен быть доступен через час или около того. Дайте мне знать, если это поможет.

Я думаю, что мы все еще сталкиваемся с этой проблемой даже с исправлениями с https://github.com/DefinitelyTyped/DefinitelyTyped/pull/16969. Вот фиктивный компонент, который я сделал, чтобы попытаться изолировать проблему:

import * as React from "react"
import { connect, MapStateToProps, MapDispatchToPropsFunction } from "react-redux"


interface RootState {
  globalA: string
  globalB: number
}

interface DumbComponentProps {
  a: string
  b: number
  c?: number
}

const DumbComponent = (props: DumbComponentProps): JSX.Element => {
  return (
    <div>Something: {props.a} {props.b} {props.c}</div>
  )
}

type ConnectedStateProps = Pick<DumbComponentProps, "a" | "b">
type ConnectedOwnProps = Pick<DumbComponentProps, "c">

const mapStateToProps: MapStateToProps<ConnectedStateProps, ConnectedOwnProps> = (
    state: RootState): ConnectedStateProps => {
  return {
    a: state.globalA,
    b: state.globalB
  }
}

const SmartComponent = connect(
  mapStateToProps
)(DumbComponent)

export default SmartComponent

Затем я где-то использую SmartComponent и передаю c (обратите внимание, что a и b должны исходить из состояния).

...
return (
  <SmartComponent c{2} />
)

Ошибка, которую я получаю:

error TS2322: Type '{ c: 2; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<DumbComponentProps, ComponentState>> & R...'.
  Type '{ c: 2; }' is not assignable to type 'Readonly<DumbComponentProps>'.
    Property 'a' is missing in type '{ c: 2; }'.

Проверяя типы в VS Code, я замечаю, что он выбирает неправильный тип для SmartComponent. Он думает, что это React.ComponentClass<DumbComponentProps> ... но это должно быть React.ComponentClass<Pick<DumbComponentProps, "c">> (т. е. он должен принимать только OwnProps. Это имеет смысл из типов, где ComponentDecorator — это функция, которая возвращает ComponentClass<T> (где T extends TOwnProps ) ... так что, к сожалению, я не знаю, почему это не отображается правильно.

Я делаю что-то явно неправильно здесь? Есть ли способ заставить компилятор шаг за шагом показывать мне, что он делает?

Похоже, что mapDistpachToProps теперь не является обязательным. Это нормально или это баг?

Обновление моего комментария выше, после небольшого поиска - я создал тестовый пример, который в настоящее время терпит неудачу (но я считаю, что не должен) и исправление типизации, которое обрабатывает мой случай, но не обрабатывает случай, когда он должен угадать, что такое OwnProps (например, connect()(DumbComponent) ). Мой набор изменений здесь:
https://github.com/DefinitelyTyped/DefinitelyTyped/compare/master...ritwik : реагировать-редукс/fix-ownprop-inference
Хотел бы помочь с решением этого, но я достиг предела своих знаний с помощью машинописного текста. Если у кого-то есть мысли о моем тестовом примере или предложения, с удовольствием их обсудим.

Просто закрытие цикла здесь - https://github.com/DefinitelyTyped/DefinitelyTyped/pull/17196 выглядит так, как будто это исправлено для нашей кодовой базы.

Было ли это решено? В настоящее время я получаю эту проблему в ^ 5.0.8 ( IntrinsicAttributes & IntrinsicClassAttributes<Component<Pick ... ). Единственная разница в том, что я использую types вместо interfaces .

кто-нибудь? к сожалению, для меня это настоящий спектакль...

@proProbe Не могли бы вы предоставить свои версии @types/react-redux , @types/react и redux , а также образец, воспроизводящий ошибку?
Также авторы пакета CC: @tkqubo @thasner @kenzierocks @clayne11 @tansongyang @nicholasboll

Извините за столь поздний ответ! Я работал с образцом, чтобы воспроизвести его. Затем я внезапно понял, что это было исправлено в @types/react-redux: "^5.0.8". Спасибо хоть!

Все еще получаю это с "^ 5.0.10" :(

"@types/react": "^15.6.4",
"redux": "3.7.2",
"@types/react-redux": "^5.0.10"

Я могу поделиться фрагментом кода с автором пакета, но, к сожалению, не публично.

Понижение до 4.4.40, как было предложено выше, сразу же устранило ошибку.

Я смог решить эту проблему в своей собственной кодовой базе, настроив тип connect для типа возвращаемого значения mapStateToProps и того, каким должен быть ownProps. Вырвано из контекста, если я хочу назвать свой список продуктов со списком идентификаторов продуктов, например:

<ProductList productIDs={productIDs} />

и иметь mapStateToProps для перевода этих идентификаторов в продукты, которые будут отображаться в списке, например:

const mapStateToProps = (state: RootState, ownProps: {productIDs: List<UUID>}) => {
  return { products: state.get('products').filter(
    (p: Product) => ownProps.productIDs.contains(p.uuid)) };
};

затем мне пришлось параметризовать connect , например:

const ProductList = connect<ProductListProps, void, {productIDs: List<UUID>}>(mapStateToProps)(ProductListComponent);

После некоторого расследования. Я нашел простое решение. Что вам нужно сделать, так это иметь «compilerOptions»: { «strict»: true } в вашем tsconfig.json, если вы подключаете компонент React.Component<,>.

Typescript 2.8.x исправляет это. Обновите и попробуйте.

Снова ломается в Typescript 3.0.1. Привет Тиен!

Разрыв с TypeScript 3.2.2 тоже.

Есть ли у этой проблемы какие-либо обновления?

У меня тоже сломалось с Typescript 3.2.2. Однако аннотация connect с помощью connect<Props> , кажется, исправляет это.

У меня такая же проблема, даже с аннотированием подключения:/

У меня тоже такая же проблема, не обновляется ли вообще?

Разрыв с TypeScript 3.2.4 тоже.

Похоже, это не скоро решится.

Всем, у кого возникла эта проблема, убедитесь, что вы правильно импортируете подключенный компонент. Я переключил уже существующий компонент на функцию connect(), когда ему нужно было получить доступ к состоянию приложения из избыточности. При этом я переключился с экспорта функции без сохранения состояния на экспорт компонента моего класса по умолчанию. Когда я не изменил способ импорта в другие файлы, появилась эта ошибка.

Это работает.

Есть ли какой-нибудь обходной путь, чтобы хотя бы заглушить эту ошибку локально?

Определенно кажется, что где-то в OwnProps и StateProps есть триггер. Я вижу эту проблему, когда у нас есть подключенный компонент Redux, у которого есть дочерние элементы.

Все, что я сделал, чтобы заглушить эту проблему, это использовать <any> :

export default connect<any>(states, actions)(SomeComponent);

также работает, если вы используете композицию:

export default compose<any>(
  connect(states, actions),
  withStyles(styles)
)(SomeFunctionalComponent);

Это должно устранить ошибку при передаче реквизита «умному»/подключенному компоненту.

РЕДАКТИРОВАТЬ: я только что перечитал ветку еще раз, и кажется, что обходной путь @themodernlife - лучший обходной путь (т.е. аннотировать соединение или композицию с использованием интерфейса или типа Props):

Разве это не уничтожает всю проверку типов и Intellisense? Так какой смысл тогда вообще добавлять типизацию? @dcefram

Да, это обходной путь, просто заставить компилятор замолчать и позволить ему собраться, чтобы это не было «остановкой показа» (или, в моем случае, чтобы я не переписал все, что не связано с TS, или не застопорился, пока не выйдет исправление). ). Хотя это не решение .

Я тоже жду исправления :)

Лучший обходной путь — вручную ввести вызов connect следующим образом:

type StateProps = {
  // Attributes that you want mapped from redux store
}
type DispatchProps = {
  // Dispatch actions
}
type OwnProps = {
  // Other props that component expects when being created
}
type Props = StateProps & DispatchProps & OwnProps;
class ExampleComponent extends React.Component<Props> { /* ... */ }

const mapStateToProps = (state: State, ownProps: OwnProps): StateProps => { /* .. */ }
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => { /* ... */ }

export default connect<StateProps, DispatchProps, OwnProps>
  (mapStateToProps, mapDispatchToProps)(ExampleComponent)

Это должно создать правильный подключенный компонент, который ожидает OwnProps при создании и не имеет другого состояния и не отправляет реквизиты.

Отрицательный. Он все еще пытается вывести типы. Вместо этого я должен переопределить вручную, набрав const , а затем вернуть его по умолчанию.

const connected: React.ComponentType<OwnProps> = connect<StateProps, DispatchProps, OwnProps>(......)(Component);
export default connected;

Столкнувшись с той же проблемой с connect(), используя "@types/react-redux": "7.0.1" и "typescript": "3.4.5" . Никакие упомянутые решения, похоже, не помогли. @TroySchmidt Можете ли вы поделиться тем, как вы использовали это «подключение» в родительском компоненте, если возможно, какой-нибудь пример кода был бы очень полезен?

Привет, у меня была похожая ошибка. react-redux, похоже, не разрешает возвращаемое значение mapStateToProps как «TInjectedProps», что вызывает неправильное исключение в помощнике Omit @types/react-redux index.d.ts:110 export type InferableComponentEnhancerWithProps .

определение типа в функции подключения решает проблему

// connect Redux
export const RCHeader = connect
<IHeaderStateToProps, //returned by mapStateToProps
 {}, // not necessary
 IHeaderProps, // props you want to pass through jsx/tsx
 IHeaderConnectedReduxStateProps, // combined from IHeaderMapStateToProps and IHeaderProps
 {}// not necessary
>(
    (state: ISettingsState ): IHeaderStateToProps => {
        return {
            headerLogoURL: state.settings.headerLogoURL
        }
    },
    undefined,
    undefined,
    { forwardRef: true }
)(Header);
{
  "dependencies": {
    "react": "^16.8.6",
    "react-redux": "^6.0.1",
    "redux": "^4.0.1"
  },
  "devDependencies": {
    "@types/react": "^16.8.17",
    "@types/react-redux": "^7.0.6",
    "react-scripts-ts": "^4.0.8",
    "typescript": "^3.4.5"
  }
}

Есть ли обновление для этого?

Недавно я пишу компонент, который бы connect редукционизировался. Когда я использую этот компонент в другом месте, все его реквизиты отсутствуют. И исправить это:

type StateProps = {
  /* some code */
};

type DispatchProps = {
  /* some code */
};

type OwnProps = {
  /* some code */
};

type Props = StateProps & DispatchProps & OwnProps;

const mapStateToProps = (state: IReduxState): StateProps => ({
  /* some code */
});

const mapDispatchToProps = (dispath: Dispatch<AnyAction>): DispatchProps => {
  /* some code */
};

const BaseComponent: React.FC<Props> = (props: Props) => {
  /* some code */
};

export const ConnectedComponent: React.ComponentType<OwnProps> = connect<
  StateProps,
  DispatchProps,
  OwnProps,
  IReduxState
>(
  mapStateToProps,
  mapDispatchToProps
)(BaseComponent);

зависимости ниже:

{
  "dependencies": {
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-redux": "^7.1.0",
    "redux": "^4.0.1",
  },
  "devDependencies": {
    "@types/react": "^16.8.22",
    "@types/react-dom": "^16.8.4",
    "@types/react-redux": "^7.1.0",
    "@types/redux": "^3.6.0",
    "typescript": "^3.5.2"
  }
}

добавление всех этих типов вместо базового вывода типа не кажется мне хорошим решением...

Это все еще кажется проблемой. Совершенно уверен, что проблема возникла в версии 7.0.2 , так как я могу установить 7.0.1 и вывод типов работает правильно.

Работает на меня.
@justemit опубликовал правильный подход, который работает в последних версиях реакции и редукции.

@justemit Спасибо, это свело меня с ума 🙌

Редактировать: я исправил проблему, используя React.FC<Props> 😅

Я думаю, что эта проблема все еще жива и здравствует в @types/react-redux@^7.1.2 :

const propTypes = {
  foo: PropTypes.number.isRequired,
  bar: PropTypes.func.isRequired
};

// inferring the Props type
interface Props extends PropTypes.InferProps<typeof propTypes> {}
// although doing it explicitly also yields the same result
interface Props {
  foo: number,
  bar: (...args: any[]) => any
}

const Foo = (props : Props) => <></> // EDIT: incorrect way to define functional components
const Foo : React.FC<Props> = (props) => <></> // EDIT: the correct way
//          ^^^^^^^^

Foo.propTypes = propTypes;
/* Foo.defaultProps = {
  foo: 1,
  bar: () => {}
} //*/

const mapStateToProps = (state : any) => ({
  foo: 1
})
const mapDispatchToProps = {
  bar: () => {}
}
const Bar = connect(mapStateToProps, mapDispatchToProps)(Foo)

const Baz = () => <Bar /> // throws an error
Type '{}' is missing the following properties from type 'Readonly<Pick<Pick<Props, never>, never> & Pick<InferProps<{ foo: Validator<number>; bar: Validator<(...args: any[]) => any>; }>, "foo" | "bar">>': foo, bar



md5-e744aa0bac3ac7f45f015259c5597ea9



Тип «ConnectedComponentClass<...>» не может быть назначен типу «ComponentType<{}>».
В типе «Только для чтения<{}>» отсутствуют следующие свойства типа «Только для чтения; bar: Validator<(...args: any[]) => any>; }>>': фу, бар

And even if typing everything explicitly helped, I agree with <strong i="16">@alexandrudanpop</strong> that it should be possible to infer those types instead of doing everything manually 🤔 

**Edit:** for anyone looking for inspiration for a workaround, I currently resort to explicitly casting using `unknown`:
```ts
// assumes `mapDispatchToProps` is an object, could be a function if used with `ReturnType`
type OwnProps = Omit<Props, keyof ReturnType<typeof mapStateToProps> | keyof mapDispatchToProps>
connect(mapStateToProps, mapDispatchToProps)(Foo) as unknown as React.ComponentType<OwnProps>

Что-то, что может помочь с выводом (все еще некоторая ручная работа), делает что-то вроде этого
Выход из примера @kdmadej

type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = typeof mapDispatchToProps;
type OwnProps = {
  a: string;
  b: number;
}

type Props = StateProps & DispatchProps & OwnProps;

const Foo = (props : Props) => <></>

const mapStateToProps = (state : any) => ({
  foo: 1
})

const mapDispatchToProps = {
  bar: () => {}
}

export default connect(mapStateToProps, mapDispatchToProps)(Foo)


// In another file
const Baz = () => <Bar /> <-- this should throw error expecting `a` and `b`

Однако проблема, с которой я сталкиваюсь, заключается в том, что я добавляю в смесь OwnProps . Использование <Bar /> любом месте должно вызвать ошибку из-за отсутствия реквизитов a и b , но это не так, и это действительно беспокоит меня (без каламбура).

Я обошел это, используя это

const ConnectedBar: React.ComponentType<OwnProps> = connect(mapStateToProps, mapDispatchToProps)(Bar);
export default ConnectedBar;

или эквивалентно

export default connect(mapStateToProps, mapDispatchToProps)(Foo) as React.ComponentType<OwnProps>;

Я исправил свои проблемы, используя React.FC<Props> для правильного ввода функционального компонента 😉
Обновил исходный пост

Есть новости по этому поводу? Как сказал @alexandrudanpop , добавление всех этих типов вместо базового вывода типов не кажется хорошим решением. Я использую 7.2.1 , и у меня все еще та же проблема.

В других моих компонентах у меня есть:

const connector = connect(mapStateToProps, mapDispatchToProps);
type PropsFromRedux = ConnectedProps<typeof connector>;
type Props = PropsFromRedux & OwnProps;

но это, похоже, не работает, если родитель также отправляет некоторые реквизиты.

Также испытывает ту же проблему.
Начал ломаться после обновления npm.
Мое исправление заключается в следующем:
export default connect(mapStateToProps)(ConnectedIntlProvider) as unknown as ComponentType<unknown>;
Как неизвестно, потому что нет OwnProps. Там должны идти только OwnProps.

Однако вот так это работает:
export default connect<StateFromProps, null, OwnProps, ApplicationState>(mapStateToProps)(viewWithIntl);

Но таким образом это не так:
export default connect<StateFromProps, DispatchFromProps, OwnProps, ApplicationState>( mapStateToProps, mapDispatchToProps, )(attachmentFormWithIntel)
И требует суффикс:
as unknown as ComponentType<OwnProps>;

С использованием
"@types/реагировать": "16.9.49",
"@types/react-redux": "^7.1.9",
"машинопись": "^4.0.3"
"редукс": "^4.0.5",
{
"зависимости": {
"реагировать": "^ 16.13.1",
"реагировать-дом": "^ 16.13.1",
"реакция-редукс": "^7.2.1",
"редукс": "^4.0.5",
},
"devDependencies": {
"@types/реагировать": "16.9.49"
"@types/react-dom": "16.9.8",
"@types/react-redux": "^7.1.9",
"машинопись": "^4.0.3"
}
}

Была ли эта страница полезной?
0 / 5 - 0 рейтинги