Search code examples
typescriptecmascript-6iteratordestructuring

How can I access array field of an object in TypeScript? Type 'unknown' must have a '[Symbol.iterator]()' method that returns an iterator


I have a helper function which updates the form based on the fieldname, e.g. if name, then form.name will be updated. If user[0].name, then name of index 0 of form.users will be updated. However I'm facing an error and it is simplified by the code below:

const example: Record<string, unknown> = {
    'a': 'haha',
    'b': [1,2,3],
};
const str = 'b.haha';
const tokens: string[] = str.split(".");
if (typeof example[tokens[0]][Symbol.iterator] === 'function') {
    const c = [...example[tokens[0]];
}

playground

I can't solve this Type 'unknown' must have a 'Symbol.iterator' method that returns an iterator. Thanks


Solution

  • Your problem is that you set the second generic argument of Record to unknown. In your case you probably want to it to be any instead:

    const example: Record<string, any> = { // <- change is in this line
        'a': 'haha',
        'b': [1,2,3],
    };
    const str = 'b.haha';
    const tokens: string[] = str.split(".");
    
    if (typeof example[tokens[0]][Symbol.iterator] === 'function') {
        const c = [...example[tokens[0]];
        console.log(c);
    }
    

    Playground

    The fundamental difference between unknown and any IMO is that you need to cast variables of type unknown actively, while you can do anything with variables of type any. This makes unknown a bit more safe since you get errors at compile time if you try to do something with a unknown variable although the code doesn't know what it is at that line.

    Personally I would keep the unknown and actually let typescript do it's magic with type guards, which automatically casts c to any[]:

    const example: Record<string, unknown> = {
        'a': 'haha',
        'b': [1,2,3],
    };
    const str = 'b.haha';
    const tokens: string[] = str.split(".");
    
    const value = example[tokens[0]];
    
    if (Array.isArray(value)) {
        const c = [...value];
        console.log(c);
    }
    

    Playground

    You might want to read up the docs about unknown and how it compares to any.