skip to Main Content

I’m having issues accessing a property in a object using a string index, where the interface is defined using in keyof.

Take this code:

interface IFilm {
    name: string;
    author: string;
}
type IExtra<T extends  {}> = {
    [index in keyof T]: number;
};

const film : IFilm = { name: "FilmName", author: "AuthorName"};
const extra : IExtra<IFilm> = {  name: 1, author: 2};

Object.keys(film).forEach(X => {
    extra[x] = 3; // Error here!!
});

Where I try to access extra[x] I got this error:

Element implicitly has an ‘any’ type because expression of type ‘any’ can’t be used to index type ‘IExtra’.

I’m getting why: typescript cannot know that x contains only string that are actually valid for the constraint in keyof T.
Thus, how can I rewrite this, or make TypeScript aware that this is valid code? I know I can using (extra as any)[x], but I’d like to be "type-checked" 🙂

2

Answers


  1. You issue is that Object.keys<T> returns a string, not a key of T.

    You need yo do a type assertion extra[x as keyof IFilm] = 3;

    If you want to iterate over typed keys, use a Map.

    Login or Signup to reply.
  2. The Object.keys doesn’t return keyof T, because TS does not guarantes that there are no other keys:

    const notAFilm = { name: '123', author: 'asd', blah: true }
    const badFilm: IFilm = notAFilm
    const badKeys = Object.keys(badFilm)
    console.log(badKeys) // ["name", "author", "blah"] 
    

    If you are sure there is no other keys, make an alternative which knows that:

    interface IFilm {
        name: string;
        author: string;
    }
    type IExtra<T extends {}> = {
        [index in keyof T]: number;
    };
    
    const film: IFilm = { name: "FilmName", author: "AuthorName" };
    const extra: IExtra<IFilm> = { name: 1, author: 2 };
    
    /** works as expected only if there is no unknown keys */
    function recordKeys<T extends {}>(o: T): (keyof T)[] {
        return Object.keys(o) as (keyof T)[]
    }
    
    recordKeys(film).forEach(x => {
        extra[x] = 3; // works fine
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search