Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

278
Visualizações
TypeScript: Typing a value based on an object key

I need some help on my TypeScript adventure.

Here's my example type:

type Target = {
  names: string[]
  addresses: {
      location: string
    }[]
};

Here's my example object:

const myTarget: Target = {
  names: ["Alex", "Nico"],
  addresses: [
    {
      location: "Miami",
    },
    {
      location: "New York",
    },
  ],
};

And here's my function example:

const changeValue = (
    key: keyof Target,
    value: string | Record<string, unknown>
) => {
 myTarget[key] = [...myTarget[key], value]
}

changeValue('names', 'Elvis')
changeValue('addresses', { location: "Atlanta" })

I've an error on the myTarget[key] saying this:

Cannot assign type '(string | Record<string, unknown>)[]' to type 'string[] & { location: string; }[]'.
Cannot assign type '(string | Record<string, unknown>)[]' to type 'string[]'.
Cannot assign type 'string | Record<string, unknown>' of type 'string'.
Cannot assign type 'Record<string, unknown>' to type 'string' .ts(2322)

From what I understand is that, for example, TypeScript is testing all combinations, including adding an object to the names array, which is invalid, or adding a string inside addresses array.

Can someone please help me to understand what's the problem and how can I handle it. ( the real project is so much more complicated, but maybe with this example I'll understand a bit..)

Thanks a lot.

about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

In general, where you want to pass a key of an object type and a value of the type of that key, you can do so like this:

const changeValue = <K extends keyof Target, V extends Target[K]>(
    key: K,
    value: V
) => {
 myTarget[key] = value; 
}

That is, you tell the compiler that value is not only the same type of some value of the object, but the same type as the one given by key.

However, you upped the difficult by playing with arrays. There is not, so far as I know, a utility type to extract the type of an array, so I wrote one:

type ArrayType<T> = T extends Array<infer U>? U : never;

Now we can use it:

const appendValue = <K extends keyof Target, V extends ArrayType<Target[K]>>(
    key: K,
    value: V
) => {
 myTarget[key] = [...myTarget[key], value] as Target[K];
}

Unfortunately, as you see, the compiler gets a little confused about the relationship between V[] and Target[K], so it needs the hint in the form of as.

Now the calls compile cleanly:

appendValue('names', 'Elvis')
appendValue('addresses', { location: "Atlanta" })

Incidentally, you do some things in your example code (though perhaps not in your actual code) that I would urge you not to do.

First, you have mutable global data, myTarget. Hic fons lacrimis, do not do this, in any language, if you can at all avoid it.

Also, mutating data in general is a bad idea. Consider this instead:

const appendValue = <K extends keyof Target, V extends ArrayType<Target[K]>>(
    target: Target,
    key: K,
    value: V
): Target => ({
    ...target,
    [key]: [...myTarget[key], value] as Target[K]
})
about 4 years ago · Juan Pablo Isaza Relatório

0

Why do you have an error ?

Answer on this question you can find here , here , here and in my article here.

Using this type string | Record<string, unknown> for value argument is not safe. It is better to infer the type of key argument:

const changeValue = <Key extends keyof Target>(
    key: Key,
    value: Target[Key][number]
) => {
    // error
    myTarget[key] = [...myTarget[key], value]
}

You have an error here, because there is no correlation (inside) function body between key and value. Such correlation exists only outisde of function, I mean, when you call this function.

Please keep in mind that key is still a union type. I think it worth using immutable approach:

type Target = {
    names: string[]
    addresses: {
        location: string
    }[]
};

const myTarget: Target = {
    names: ["Alex", "Nico"],
    addresses: [
        {
            location: "Miami",
        },
        {
            location: "New York",
        },
    ],
};


const withTarget = <
    Obj extends Record<string, unknown[]>
>(target: Obj) => <
    Key extends keyof Obj
>(
    key: Key,
    value: Obj[Key][number]
): Obj => ({
    ...target,
    [key]: target[key].concat(value)
})

const changeValue = withTarget(myTarget);
const result = changeValue('names', 'Elvis')
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda