Following is the type that I wanted to create with index signature in TypeScript.
export interface LoginState {
account: {
[userName: string]: string;
[password: string]: string;
};
}
But, I'm getting an error as stated in the title of this question.
The tool complains/highlighted the password field.
I found the following answer: The error of 'Duplicate string index signature' at Reactjs with Typescript But that didn't help for my problem.
Can anyone point me the mistake I have done here?
Please feel free to ask if require further clarifications.
Cheers, RSF
P.S adding complete component implementation:
import * as React from "react";
import { User } from "./../interfaces/User";
import { SecurityService } from "./../services/SecurityService";
export interface LoginProps {
onLogged: (user: User) => void;
}
export interface LoginState {
currentUser: User | null;
account: {
[userName: string]: string;
[password: string]: string;
};
}
export class Login extends React.Component<LoginProps, LoginState> {
constructor(props: LoginProps) {
super(props);
this.state = {
currentUser: null,
account: {
userName: "",
password: ""
}
};
}
handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
};
handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
let account = { ...this.state.account };
account[e.currentTarget.name] = e.currentTarget.value;
};
render() {
return (
<div>
<h1>Login</h1>
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="userName">Username</label>
<input
autoFocus
onChange={this.handleChange}
name="userName"
id="userName"
type="text"
className="form-control"
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
onChange={this.handleChange}
name="password"
id="password"
type="text"
className="form-control"
/>
</div>
<button className="btn btn-primary">Login</button>
</form>
</div>
);
}
}
From Typescript Handbook
Similarly to how we can use interfaces to describe function types, we can also describe types that we can “index into” like a[10], or ageMap["daniel"]. Indexable types have an index signature that describes the types we can use to index into the object, along with the corresponding return types when indexing
When you use index types
you are just telling typescript what return type you get when a custom type is indexed.
So you just need to tell Typescript that when you index account
with a string type, a string type will be returned. That's all.
export interface LoginState {
currentUser: User | null;
account: {
// Tells Typescript that a string index on account would return a string
[k: string]: string;
username: string;
password: string;
address: string;
anotherField: string;
};
}
By defining it like this:
[userName: string]: string;
[password: string]: string; // This is a duplicate string index
You are doing this:
[k1: string]: string;
[k2: string]: string; // This is a duplicate string index
Which is wrong because you're telling Typescript the same thing twice: If you index account with a string, you'll get a string. If you index account with a string, you'll get a string.
Later, if you wanted to introduce number
type fields called id
and age
to account
, your definition would look like this:
export interface LoginState {
currentUser: User | null;
account: {
// Tells Typescript that a string index on account would return a string OR a number
[k: string]: string | number;
username: string;
password: string;
address: string;
anotherField: string;
id: number;
age: number;
};
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With