Subscribe on changes!

Using v-for on an object with key/value, the key is typed as number

avatar
Jul 20th 2023

Vue version

3.3.4

Link to minimal reproduction

https://play.vuejs.org/#eNp9UmFLwzAQ/StHELZB3XD7VraBygT94ET9ZoTV7la7pUlI0jop/e9eUrdVkPVDyb17effetTW71npYlchiNrWpybUDi67UIBKZzThzlrM5l6mS1oFD65YfW0xdDDW87WKwzuQyez8coIEZ1FwC7PD7KoZelYgSx73oFxqfIC4bLrvCd6VMXa4kKfQTk9HtVjMCquhiWw1gNm8nGLJpJKwuas9uYgiHcbMKytNRm4a8U+Gw0CJxSBXAdJ1XUF1ulKF8/WAn8uYGkMtORM4gJpQ49A5LAHrq+o/ZPvUiCBoDaGguyY9In9jTUWcqi2iTlHWTZ8OtVZLWHUJwlqpC5wLNUns92jatth3FWSKE+noImDPk8oCnn5ju/sG3du8xzp4MWjQVcnbsOVoOUijfXrw84p7Ox2ah1qUg9pnmM1olSu+xpd2Uck22O7zg9r7Qyjj6UK92sXco7SGUN+qZTeBzRv/c7ZnoJ7uT4STco8/Kmh/qs+TD

Steps to reproduce

Use v-for on an object with value and key as iterators, like in https://vuejs.org/guide/essentials/list.html#v-for-with-an-object Then check the type of the key variable (number)

What is expected?

The key type should be string

What is actually happening?

The key type is number

System Info

No response

Any additional comments?

My guess is that it is typed as a number because v-for is usually used on an array, and in that case the second argument is the index. But v-for also supports iterating on an object and in that case it will be a string.

avatar
Jul 20th 2023
/**
 * v-for object
 */
export function renderList<T>(
  source: T,
  renderItem: <K extends keyof T>(
    value: T[K],
    key: K,
    index: number
  ) => VNodeChild
): VNodeChild[]

const testObject: { [k: string]: string } = { key1: 'value2', key2: 'value2' }

type k = keyof typeof testObject . the type K is string | number

maybe this is the problem

avatar
Jul 20th 2023

Thanks for your input, it seems like the types for v-for are declared here: https://github.com/vuejs/core/blob/3.2/packages/runtime-core/src/helpers/renderList.ts#L41 And we can see that the second argument key gets the type K which is K extends keyof T (with T the type of the v-for source). So in my case keyof { [key: string]: string } evaluates to string | number. This was introduced with Typescript 2.9: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#support-number-and-symbol-named-properties-with-keyof-and-mapped-types

The use of keyof seems logical, however in practice using v-for on an object will always provide the key as a string, so maybe Vue should directly type the key as string?