Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duplicate string index signature.ts(2374)

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.

enter image description here

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>
   );
  }
 }
like image 617
RSF Avatar asked May 24 '19 13:05

RSF


1 Answers

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;
  };
}
like image 92
PrashanD Avatar answered Sep 29 '22 23:09

PrashanD