Skip to content

When using keyof typeof, downstream code inference breaks in unexpected ways #23649

Closed
@AlexGalays

Description

@AlexGalays

TypeScript Version: 2.8.3 and next

Search Terms:
keyof inference

Code

export function Set<K extends string>(...keys: K[]): Record<K, true | undefined> {
  const result = {} as Record<K, true | undefined>
  keys.forEach(key => result[key] = true)
  return result
}

export function keys<K extends string, V>(obj: Record<K, V>): K[] {
  return Object.keys(obj) as K[]
}

type Obj = { code: LangCode }


/* No duplication - Derived */
const langCodeSet = Set('fr', 'en', 'es', 'it', 'nl')
export type LangCode = keyof typeof langCodeSet
export const langCodes = keys(langCodeSet)

// Does not compile (???)
const arr: Obj[] = langCodes.map(code => ({ code }))



/* Duplication */
export type LangCode2 = 'fr' | 'en' | 'es' | 'it' | 'nl'
export const langCodes2: LangCode2[] = ['fr', 'en', 'es', 'it', 'nl']

// Compiles
const arr2: Obj[] = langCodes2.map(code => ({ code }))

Expected behavior:
Everything should compile

Actual behavior:
Only the straightforward code compiles. The two are functionally equivalent.

Playground Link:
https://www.typescriptlang.org/play/#src=%0Aexport%20function%20Set%3CK%20extends%20string%3E(...keys%3A%20K%5B%5D)%3A%20Record%3CK%2C%20true%20%7C%20undefined%3E%20%7B%0A%20%20const%20result%20%3D%20%7B%7D%20as%20Record%3CK%2C%20true%20%7C%20undefined%3E%0A%20%20keys.forEach(key%20%3D%3E%20result%5Bkey%5D%20%3D%20true)%0A%20%20return%20result%0A%7D%0A%0Aexport%20function%20keys%3CK%20extends%20string%2C%20V%3E(obj%3A%20Record%3CK%2C%20V%3E)%3A%20K%5B%5D%20%7B%0A%20%20return%20Object.keys(obj)%20as%20K%5B%5D%0A%7D%0A%0Atype%20Obj%20%3D%20%7B%20code%3A%20LangCode%20%7D%0A%0A%0A%2F*%20No%20duplication%20-%20Derived%20*%2F%0Aconst%20langCodeSet%20%3D%20Set('fr'%2C%20'en'%2C%20'es'%2C%20'it'%2C%20'nl')%0Aexport%20type%20LangCode%20%3D%20keyof%20typeof%20langCodeSet%0Aexport%20const%20langCodes%20%3D%20keys(langCodeSet)%0A%0A%2F%2F%20Does%20not%20compile%20(%3F%3F%3F)%0Aconst%20arr%3A%20Obj%5B%5D%20%3D%20langCodes.map(code%20%3D%3E%20(%7B%20code%20%7D))%0A%0A%0A%0A%2F*%20Duplication%20*%2F%0Aexport%20type%20LangCode2%20%3D%20'fr'%20%7C%20'en'%20%7C%20'es'%20%7C%20'it'%20%7C%20'nl'%0Aexport%20const%20langCodes2%3A%20LangCode2%5B%5D%20%3D%20%5B'fr'%2C%20'en'%2C%20'es'%2C%20'it'%2C%20'nl'%5D%0A%0A%2F%2F%20Compiles%0Aconst%20arr2%3A%20Obj%5B%5D%20%3D%20langCodes2.map(code%20%3D%3E%20(%7B%20code%20%7D))

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFixedA PR has been merged for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions