Orelus
Orelus

Reputation: 1023

Property does not exists on array element

I'm trying to return an array containing an initialized object and a number.

However I get the following error:

Property 'foo' does not exist on type 'number | IObj' Property 'foo' does not exist on type 'number'

interface IObj {
    [k: string]: string
}

function test(fields: string[]){
    const foo: IObj = {}
    fields.forEach((x) => foo[x] = 'baz')
    return [foo, 1]   
}
const [foo, x] = test(['foo'])
foo.foo

How can I fix this ?

Upvotes: 1

Views: 561

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249506

For array literals by default typescript will infer an array, so when destructuring occurs each element will be IObj | number, the information that the first element is IObj and the second is a number will be lost.

In 3.4, recently released you can use as const to get the compiler to infer a readonly tuple (return [foo, 1] as const)

Or you can use an explicit type annotation to tell the compiler you want a tuple:

interface IObj {
    [k: string]: string
}

function test(fields: string[]) : [IObj, number]{
    const foo: IObj = {}
    fields.forEach((x) => foo[x] = 'baz')
    return [foo, 1]  
}
const [foo, x] = test(['foo'])
foo.foo

If you are going to use constants for the fields parameter, might I suggest a more type safe version of your code:

function test<K extends string>(fields: K[]) : [Record<K, string>, number]{
    const foo = {} as Record<K, string>
    fields.forEach((x) => foo[x] = 'baz')
    return [foo, 1]  
}
const [foo, x] = test(['foo'])
foo.foo //ok
foo.foo2 // err

Upvotes: 1

Related Questions