首页 > 解决方案 > 打字稿通用状态更改函数类型转换错误

问题描述

我正在创建一个通用函数来更改状态。

错误信息:

TS2345: Argument of type '() => { [x:string]: string }' is not assignable to parameter of type 'IUserSignUpState | Pick<IUserSignUpState, "url" | "errors"> | ((prevState: Readonly<IUserSignUpState>, props: Readonly<IUserSignUpState>) => IUserSignUpState | Pick<...> | null) null'.

Type '() => { [x: string] string; }' is not assignable to type '(prevState: Readonly<IUserSignUpState>, props: Readonly<IUserSignUpState>) => IUserSignupState | Pick<IUserSignUpState>, "url" | "errors" | null'. 

Type '{ [x: string]: string; }' is not assignable to type 'IUserSignUpState | Pick<IUserSignUpState, "url" | "errors"> | null'.

Type '{ [x: string]: string; }' is missing the following properties from type 'Pick<IUserSignUpState, "url" | "errors">': url, errors.

这是通用更改功能的示例:

./UserSignUp.tsx


interface IUserSignUpState {
  url: string;
  errors: string[];
  // following can be used, but will lose type checking (*)
  // [key: string]: string;
}

class UserSignUp extends React.Component<{}, IUserSignUpState>
  state = {
    url: '',
    name: '',
    errors: [],
  };

  render() {
    const { url, errors } = this.state;
    return (
      <form>
        <input type="text" name="url" value={url} onChange={this.change} />
        <input type="text" name="name" value={name} onChange={this.change} />
      <form>
    )
  }

  change = (event:React.ChangeEvent<HTMLInputElement>) => {
    const name = event.target.name;
    const value = event.target.value;

    // gives error here:
    this.setState(() => {
      return {
        [name]: value
      }
    })
  }
};

在此示例中,更改事件应该只允许更新url: string;andname: string;和 not errors: []

我应该定义'url'和'name'类型并以某种方式在更改函数中重用它们吗?


*在 Typescript 文档中,它声明可以使用可索引类型。但是,这样做我将失去类型检查。副作用是我可能还设置了“错误”状态,这通常不应该通过更改功能实现。


更新:根据这个Stackoverflow Question中的答案,以下解决方案是可能的:

拆分界面:

interface IInputState {
  url: string;
}

interface IUserSignUpState extends IInputState {
  errors: string[];
}

并通过以下方式重新使用该接口:

this.setState({ [name]: value } as Partial<IInputStates>)

或者:

const name = event.target.name as keyof IInputStates;
const value = event.target.value;

this.setState(():IInputStates => {
  return { [name]: value }
});

标签: reactjstypescriptreact-state

解决方案


使用类型不会阻止更改错误属性,因为类型检查仅适用于编译时。当它到达浏览器时,它仍将作为普通的旧动态 JavaScript 运行。

如果您想限制更改功能作用的属性,您需要检查属性名称,例如针对允许值的数组。

作为旁注,您的输入缺少该name属性。

 render() {
    const { url, errors } = this.state;
    return (
      <form>
        <input type="text" name="url" value={url} onChange={this.change} />
        <input type="text" name="name" value={name} onChange={this.change} />
      <form>
    )
  }

  change = (event:React.ChangeEvent<HTMLInputElement>) => {
    const name = event.target.name;
    const value = event.target.value;

    if (!isValidProperty(name)) return;

    this.setState({ [name]: value } as Partial<IInputStates>)
  }

  // Dummy instance to force a compile warning and ensure we capture all the property names
  const inputExample: IInputStates = { url: '' };
  const inputKeys = Object.keys(inputExample);

  function isValidProperty(name: string): name is keyof IInputStates {
    return inputKeys.includes(name);
  }

推荐阅读