Definitelytyped: 4.4.41 中引入的@types/react-redux 中的 connect() 问题

创建于 2017-06-06  ·  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 不小心交换TOwnPropsTMergedProps / 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 :react-redux/fix-ownprop-inference
想帮助解决这个问题,但我用打字稿达到了我的知识极限。 如果有人对我的测试用例或建议有想法,很乐意讨论这些。

只是在这里关闭循环 - https://github.com/DefinitelyTyped/DefinitelyTyped/pull/17196看起来它为我们的代码库解决了这个问题。

这解决了吗? 我目前在 ^5.0.8 ( IntrinsicAttributes & IntrinsicClassAttributes<Component<Pick ... ) 中遇到了这个问题。 唯一的区别是我使用types而不是interfaces

任何人? 不幸的是,这对我来说是一个真正的表演者......

@proProbe您能否提供您的@types/react-redux@types/reactredux版本以及重现错误的示例?
还有 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 立即消除了错误。

我能够在我自己的代码库中通过对 mapStateToProps 的返回值类型和我希望 ownProps 的类型参数化 connect 来解决这个问题。 如果我想使用产品 id 列表调用我的产品列表,则断章取义,例如:

<ProductList productIDs={productIDs} />

并有mapStateToProps将这些 id 转换为要显示在列表中的产品,例如:

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);

经过一番调查。 我找到了一个简单的解决方案。 如果您要连接 React.Component<,> 组件,您只需在 tsconfig.json 中添加 "compilerOptions": { "strict": true }。

Typescript 2.8.x 修复了这个问题。 升级并试一试。

在 Typescript 3.0.1 中再次中断。 嗨,天!

也打破了 TypeScript 3.2.2。

这个问题有更新吗?

Typescript 3.2.2 也为我打破了。 但是,用connect<Props>注释connect #$ 似乎可以解决这个问题。

我有同样的问题,即使注释连接:/

我也有同样的问题,没有更新吗?

也打破了 TypeScript 3.2.4。

看来这不会很快得到解决。

对于遇到此问题的每个人,请确保您正确导入连接的组件。 一旦需要从 redux 访问应用程序状态,我将一个已经存在的组件切换为具有 connect() 函数。 在执行此操作时,我从导出无状态函数切换为默认导出我的类组件。 当我没有更改在其他文件中导入它的方式时,会弹出此错误。

这是工作。

是否有任何解决方法至少可以在本地消除此错误?

在 OwnProps 与 StateProps 的某个地方似乎肯定存在触发器。 我看到了这个问题,我们有带有子的 Redux 连接组件。

我为解决这个问题所做的只是使用<any>

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

如果您使用 compose 也可以:

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

在将道具传递给“智能”/连接组件时,这应该使错误静音。

编辑:我只是再次重新阅读该线程,似乎@themodernlife解决方法是更好的解决方法(即使用 Props 接口或类型注释连接或组合):

这不是也破坏了所有的类型检查和智能感知吗? 那么添加类型有什么意义呢? @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;

使用 "@types/react-redux": "7.0.1" 和 "typescript": "3.4.5" 的 connect() 面临同样的问题。 没有提到的解决方案似乎有帮助。 @TroySchmidt如果可能的话,你能否分享一下你是如何在父组件中使用这个“连接”的,一些示例代码会很有帮助

你好,我遇到了类似的错误。 react-redux 似乎没有将 mapStateToProps 的返回值解析为“TInjectedProps”,这会导致 Omit helper @types/react-redux index.d.ts:110 export type InferableComponentEnhancerWithProps中的错误排除。

在connect函数中定义类型解决了问题

// 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到 redux 的组件。 当我在其他地方使用这个组件时,它的所有道具都不见了。 并通过以下方式修复它:

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发布了适用于最新版本的 react 和 redux 的正确方法。

@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添加到组合中时。 由于缺少道具ab ,在任何地方使用<Bar />应该会引发错误,但事实并非如此,而且它真的让我很烦(没有双关语的意思)。

我用这个解决了这个问题

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/react": "16.9.49",
"@types/react-redux": "^7.1.9",
“打字稿”:“^4.0.3”
"redux": "^4.0.5",
{
“依赖”:{
“反应”:“^16.13.1”,
“反应域”:“^16.13.1”,
"react-redux": "^7.2.1",
"redux": "^4.0.5",
},
“开发依赖”:{
“@types/react”:“16.9.49”
"@types/react-dom": "16.9.8",
"@types/react-redux": "^7.1.9",
“打字稿”:“^4.0.3”
}
}

此页面是否有帮助?
0 / 5 - 0 等级