reactjs + typescript 获取错误:类型“字符串”不可分配给类型“从不”

时间:2021-07-13 08:10:04

标签: javascript reactjs typescript

在完成 axios 请求后,我尝试使用 componentDidMount 设置状态,但出现错误 Type 'string' is not assignable to type 'never'.

下面是代码

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

import axios from 'axios';

import {
  updateFilterByCategory,
  UpdateFilterRequest,
} from 'ducks/search/filters/reducer';

import { GlobalState } from 'ducks/rootReducer';
import { APPLY_BTN_TEXT } from '../constants';

interface OwnProps {
  categoryId: string;
}

interface StateFromProps {
  value: string;
}

interface DispatchFromProps {
  updateFilter: (
    categoryId: string,
    value: string | undefined,
  ) => UpdateFilterRequest;
}

export type InputFilterProps = StateFromProps & DispatchFromProps & OwnProps;

export interface InputFilterState {
  value: string;
  dropDownValue: {};
}

export class InputFilter extends React.Component<
  InputFilterProps,
  InputFilterState
> {
  constructor(props) {
    super(props);

    this.state = {
      value: props.value,
      dropDownValue: {dept: [],
      items: [],
      emp: [],
      }
    };
  }

  componentDidMount = (prevProps: StateFromProps) => {
    axios.get("/api/data")
      .then(response=>{
        Object.keys(response["result"]).map((key, value)=>{
          
          this.setState(prevState => {
            let dropDownValue = {...prevState.dropDownValue};
            dropDownValue[key] = value
            return {dropDownValue}
          })
        })
      })
      .catch(error=>{
        console.log(error)
      })
  };

  componentDidUpdate = (prevProps: StateFromProps) => {
    const newValue = this.props.value;
    if (prevProps.value !== newValue) {
      this.setState({ value: newValue || '' });
    }
  };

  onApplyChanges = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    if (this.state.value) {
      this.props.updateFilter(this.props.categoryId, this.state.value);
    } else {
      this.props.updateFilter(this.props.categoryId, undefined);
    }
  };

  onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {

    this.setState({ value: e.target.value });
  };
  
  render = () => {
    const { categoryId } = this.props;
    return (
      <form
        className="input-section-content form-group"
        onSubmit={this.onApplyChanges}
      >

             <input
             list={categoryId}
             className="form-control dropdown-input"
             name={categoryId}
             id={categoryId}
             onChange={this.onInputChange}
             value={this.state.value}
           />
        <button name={categoryId} className="btn btn-default" type="submit">
          {APPLY_BTN_TEXT}
        </button>
      </form>
    );
  };
}

export const mapStateToProps = (state: GlobalState, ownProps: OwnProps) => {
  const filterState = state.search.filters;
  const value = filterState[state.search.resource]
    ? filterState[state.search.resource][ownProps.categoryId]
    : '';
  return {
    value: value || '',
  };
};

export const mapDispatchToProps = (dispatch: any) =>
  bindActionCreators(
    {
      updateFilter: (categoryId: string, value: string | undefined) =>
        updateFilterByCategory({ categoryId, value }),
    },
    dispatch
  );

export default connect<StateFromProps, DispatchFromProps, OwnProps>(
  mapStateToProps,
  mapDispatchToProps
)(InputFilter);

错误日志

#23 59.03 ERROR in /app/static/js/pages/SearchPage/SearchFilter/FilterSection/index.tsx
#23 59.03 ./js/pages/SearchPage/SearchFilter/FilterSection/index.tsx
#23 59.03 [tsl] ERROR in /app/static/js/pages/SearchPage/SearchFilter/FilterSection/index.tsx(48,15)
#23 59.03       TS2322: Type '{ categoryId: string; }' is not assignable to type 'Readonly<Omit<never, "value" | "updateFilter"> & OwnProps>'.
#23 59.03   Property 'categoryId' is incompatible with index signature.
#23 59.03     Type 'string' is not assignable to type 'never'.
#23 59.03  @ ./js/pages/SearchPage/SearchFilter/index.tsx 5:0-44 15:40-53
#23 59.03  @ ./js/pages/SearchPage/index.tsx 11:0-42 88:36-48
#23 59.03  @ ./js/index.tsx 21:0-44 48:69-79
#23 59.03 
#23 59.03 ERROR in /app/static/js/pages/SearchPage/SearchFilter/InputFilter/index.spec.tsx
#23 59.03 [tsl] ERROR in /app/static/js/pages/SearchPage/SearchFilter/InputFilter/index.spec.tsx(31,43)
#23 59.03       TS2786: 'InputFilter' cannot be used as a JSX component.
#23 59.03   Its instance type 'InputFilter' is not a valid JSX element.
#23 59.03     Types of property 'componentDidMount' are incompatible.
#23 59.03       Type '(prevProps: StateFromProps) => void' is not assignable to type '() => void'.
#23 59.03 
#23 59.03 ERROR in /app/static/js/pages/SearchPage/SearchFilter/InputFilter/index.tsx
#23 59.03 ./js/pages/SearchPage/SearchFilter/InputFilter/index.tsx
#23 59.03 [tsl] ERROR in /app/static/js/pages/SearchPage/SearchFilter/InputFilter/index.tsx(54,3)
#23 59.03       TS2416: Property 'componentDidMount' in type 'InputFilter' is not assignable to the same property in base type 'Component<InputFilterProps, InputFilterState, any>'.
#23 59.03   Type '(prevProps: StateFromProps) => void' is not assignable to type '() => void'.
#23 59.03  @ ./js/pages/SearchPage/SearchFilter/FilterSection/index.tsx 9:0-41 19:43-54
#23 59.03  @ ./js/pages/SearchPage/SearchFilter/index.tsx 5:0-44 15:40-53
#23 59.03  @ ./js/pages/SearchPage/index.tsx 11:0-42 88:36-48
#23 59.03  @ ./js/index.tsx 21:0-44 48:69-79
#23 59.03 
#23 59.03 ERROR in /app/static/js/pages/SearchPage/SearchFilter/InputFilter/index.tsx
#23 59.03 ./js/pages/SearchPage/SearchFilter/InputFilter/index.tsx
#23 59.03 [tsl] ERROR in /app/static/js/pages/SearchPage/SearchFilter/InputFilter/index.tsx(138,3)
#23 59.03       TS2345: Argument of type 'typeof InputFilter' is not assignable to parameter of type 'ComponentType<never>'.
#23 59.03   Type 'typeof InputFilter' is not assignable to type 'ComponentClass<never, any>'.
#23 59.03     Construct signature return types 'InputFilter' and 'Component<never, any, any>' are incompatible.
#23 59.03       The types of 'props' are incompatible between these types.
#23 59.03         Type 'Readonly<InputFilterProps> & Readonly<{ children?: ReactNode; }>' is not assignable to type 'never'.
#23 59.03  @ ./js/pages/SearchPage/SearchFilter/FilterSection/index.tsx 9:0-41 19:43-54
#23 59.03  @ ./js/pages/SearchPage/SearchFilter/index.tsx 5:0-44 15:40-53
#23 59.03  @ ./js/pages/SearchPage/index.tsx 11:0-42 88:36-48
#23 59.03  @ ./js/index.tsx 21:0-44 48:69-79
#23 59.03 
#23 59.03 webpack 5.6.0 compiled with 4 errors in 53077 ms
#23 59.38 npm ERR! code ELIFECYCLE
#23 59.38 npm ERR! errno 2
#23 59.38 npm ERR! static@1.0.0 build: `cross-env TS_NODE_PROJECT='tsconfig.webpack.json' webpack --progress --config webpack.prod.ts`
#23 59.38 npm ERR! Exit status 2
#23 59.38 npm ERR! 
#23 59.38 npm ERR! Failed at the static@1.0.0 build script.
#23 59.38 npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
#23 59.39 
#23 59.39 npm ERR! A complete log of this run can be found in:
#23 59.39 npm ERR!     /root/.npm/_logs/2021-07-13T07_55_35_192Z-debug.log

尝试在 Argument of type 'any' is not assignable to type 'never'

中寻找答案

由于我是 react 和 typescript 的新手,尽管在互联网上寻找答案,但无法解决。

我观察到,如果我删除 componentDidMount,它可以正常构建而不会出错。如果我从 prevProps: StateFromProps 中删除 componentDidMount = (prevProps: StateFromProps) 并保留 componentDidMount = () 那么它也可以正常工作。

我做错了什么?

提前致谢!

1 个答案:

答案 0 :(得分:0)

不管你的问题是什么,你的代码都有很多问题。

其中一个错误地使用了 axios 响应。

axios.get("/api/data")
      .then(response=>{
        Object.keys(response["result"]).map((key, value)=>{

您似乎正在尝试从请求 result 访问 body。 为此,您应该通过 response.data.result;

访问它

除此之外,出现的问题的根源在于您错误地声明了您的状态 interface

export interface InputFilterState {
  value: string;
  dropDownValue: {};
}

{} 断言 dropDownValue 类型意味着此密钥只能包含 EMPTY OBJECT (never)。 您正尝试使用基于 dropDownValue 的密钥 (string) 访问 dropDownValue[key] 中的某些属性。 因此,TypeScript 抱怨您无法从声明为空对象的对象中检索带有字符串键的值。

为了相应地声明它,您可以在界面中声明正确的 dropDownValue 类型。

export interface InputFilterState {
  value: string;
  dropDownValue: {
      value: props.value,
      dropDownValue: {
        dept: [],
        items: [],
        emp: [],
      }
    };
}