0

I have a class like this:

interface UserProps {
  name: string
  age: number
}

export class User {
  constructor(private data: UserProps) {}

  get(propName: string): number | string {
    return this.data[propName]
  }
}

and I don't know why I get this error: "Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'UserProps'.
No index signature with a parameter of type 'string' was found on type 'UserProps'
"

any advice?

Ehsan
  • 766
  • 10
  • 17
  • It means that you never check what `propName` is but you're using it to access a property from `UserProps`. So if `propName = "foo"` TS has no way of knowing what would be returned from `this.data[propName]`. Therefore, it implicitly assigns it `any`. [Element implicitly has an 'any' type because expression of type 'string' can't be used to index](https://stackoverflow.com/q/57086672) – VLAZ Aug 24 '21 at 10:42

1 Answers1

1

Your error occurs because you can't use any string as the key, only a subset (name and age). Set keyof UserProps as the type for propName:

interface UserProps {
  name: string
  age: number
}

export class User {
  constructor(private data: UserProps) {}

  get<T extends keyof UserProps>(propName: T): UserProps[T] {
    return this.data[propName]
  }
}
Guerric P
  • 30,447
  • 6
  • 48
  • 86
  • This isn't enough of an improvement, IMO - `user.get("age")` still returns `number | string` which is misleading, at the very least. – VLAZ Aug 24 '21 at 10:43
  • @VLAZ I think this is a good solution however I think this error should not happen. – Ehsan Aug 24 '21 at 10:47
  • @ehsan it's your code that is sloppy. For it to work, TS also has to be sloppy. Which causes an error. The solution is not good *enough* because the resulting type doesn't necessarily match what it should be. That's what I was highlighting. – VLAZ Aug 24 '21 at 10:49