我正在创建一个通用函数来更改状态。
错误消息:
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;
和name: string;
,而不是errors: []
。
我应该定义“ url”和“ name”类型,然后以某种方式在更改功能中重用它们吗?
*在打字稿文档中,指出可以使用Indexable types。但是,这样做将丢失类型检查。而且还有一个副作用,就是我还可以设置“错误”状态,而更改功能通常是不可能的。
更新:根据此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 }
});
答案 0 :(得分:1)
使用类型不会阻止errors属性更改,因为类型检查仅在编译时适用。当它到达浏览器时,仍然会像普通的旧动态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);
}
答案 1 :(得分:0)
有一些解决方案:
this.setState<never>({ [name]: value } as Partial<IInputStates>)
或
this.setState({ [name]: value } as Pick<IInputStates, keyof IInputStates>);
git中有一个未解决的问题,看看: cannot setState with dynamic key name type-safe