简体   繁体   English

InteliJ:Typescript 自动检查 {} object 针对接口?

[英]InteliJ: Typescript auto check {} object against an interface?

Here is example offending code of React component that is incorrectly connected to Redux.这是错误连接到 Redux 的 React 组件的示例违规代码。

import React from 'react';
import { View, StyleSheet, ViewStyle, Text } from 'react-native';
import { connect } from "react-redux";
import { StoreState } from "../../store/storeState/storeState";
import { LogFactory, Logger } from "../../vlabs-js/general/logging/log";

interface DevCompProps {
    counter: number
}

class UnconnectedDevComp extends React.Component<DevCompProps> {
    private logger: Logger;

    constructor(props: DevCompProps) {
        super(props);

        this.logger = LogFactory.fromComp('DevComp');
    }

    render() {
        this.logger.info(`render(): props='${this.props.counter}'`);

        return <View style={{flexDirection: 'row', borderWidth: 3, borderColor: 'black', padding: 5}}>
            <Text>Counter:</Text>
            <Text>{this.props.counter}</Text>
        </View>
    }
}

const mapStateToProps = (state: StoreState) => {
    return {
        number: state.devState.counter
    };
};


export const DevComp = connect(mapStateToProps)(UnconnectedDevComp)

For the code to work correctly mapStateToProps should be为了使代码正常工作 mapStateToProps 应该是


const mapStateToProps = (state: StoreState) => {
    return {
        counter: state.devState.counter
    };
};

Instead of代替


const mapStateToProps = (state: StoreState) => {
    return {
        number: state.devState.counter
    };
};

Is there a way to Compile/InteliJ-Warn check that the object returned by mapStateToProps matched the interface有没有办法编译/InteliJ-Warn 检查 mapStateToProps 返回的 object 是否与接口匹配

interface DevCompProps {
    counter: number
}

So such a mistake would be flagged by IDE and not have to found by hand.所以这样的错误会被 IDE 标记,而不必手动发现。

The short answer is "no" because all the solutions here suck.简短的回答是“不”,因为这里的所有解决方案都很糟糕。 You'd probably have better luck dealing with function components and useSelector hooks.处理 function 组件和useSelector钩子可能会更好。

When you map with a wrong key, your composed DevComp will be a component which requires that a counter prop be passed in when you call it so typescript gets that part right.当您使用错误的键 map 时,您的组合DevComp将是一个组件,当您调用它时需要传入一个counter道具,因此 typescript 得到该部分正确。

You can get the error to be raised by setting some of the generics on the connect function, but this seems like a pain.您可以通过在connect function 上设置一些 generics 来引发错误,但这似乎很痛苦。 The variables that we would set are the first, which is the props returned from mapStateToProps , and the third, which is the props that you expect the component to be called with.我们要设置的变量是第一个,它是从mapStateToProps返回的道具,第三个是您希望调用组件的道具。

const DevComp = connect<DevCompProps, {}, {}>(mapStateToProps)(UnconnectedDevComp)

Likewise, you can get an error to be raised by setting the return type on mapStateToProps to Partial<DevCompProps> .同样,您可以通过将mapStateToProps上的返回类型设置为Partial<DevCompProps>来引发错误。

You would need to override some of the types in the react-redux package in order to get that inference automatically.您需要覆盖react-redux package 中的某些类型才能自动获得该推断。 But that sucks too.但这也很糟糕。

We want to make it such that the props returned from mapStateToProps cannot have any keys which are not present in the component props.我们希望从mapStateToProps返回的 props 不能包含组件 props 中不存在的任何键。

You can't do it by manipulating the MapStateToProps type.您不能通过操作MapStateToProps类型来做到这一点。 That has three variables, but none represent the type of the component to be mapped.这有三个变量,但没有一个代表要映射的组件的类型。 What you need is for TStateProps to be restricted.您需要限制TStateProps

export type MapStateToProps<TStateProps, TOwnProps, State = DefaultRootState> =
    (state: State, ownProps: TOwnProps) => TStateProps;

Ultimately the issue is the two-step nature of the connect HOC.最终的问题是connect HOC 的两步性质。 The creation of the "connector" is separate from applying it to a component, so the connector cannot depend on that component. “连接器”的创建与将其应用于组件是分开的,因此连接器不能依赖于该组件。

It's perfectly fine to do this:这样做完全没问题:

const myWrapper = connect(mapStateToProps);

and get the type并获取类型

InferableComponentEnhancerWithProps<{ number: number; } & DispatchProp<AnyAction>, {}>

myWrapper is a function which can wrap any component and will add a prop number to it. myWrapper是一个 function ,它可以包装任何组件并为其添加一个道具number It doesn't know anything about the type of component that it will be applied to and does not care whether that component actually wants a prop number .它不知道要应用的组件类型,也不关心该组件是否真的需要一个 prop number

You would need to define your own function that combines the two steps into one function with two arguments so that the arguments can infer types from each other. You would need to define your own function that combines the two steps into one function with two arguments so that the arguments can infer types from each other. I don't have a complete solution.我没有完整的解决方案。 connect has 15 different overloads and this type signature only describes one. connect有 15 个不同的重载,这个类型签名只描述了一个。 Also the implementation is an error, but the function typing does what you want.实现也是一个错误,但是 function 键入可以满足您的要求。

const myConnect = <InnerProps, MappedProps extends Partial<InnerProps> , State = DefaultRootState>(
  mapStateToProps: (state: State) => MappedProps, Component: ComponentType<InnerProps>
  ): ComponentType<Omit<InnerProps, keyof MappedProps>> => {
    return connect(mapStateToProps)(Component);
}

export const DevComp = myConnect(mapStateToProps, UnconnectedDevComp)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM