Andrew Eisenberg
Andrew Eisenberg

Reputation: 28757

Why does typescript complain about a computed property name?

Using typescript Version 3.7.5. I have these two simple types and I would expect that either both of them compile or neither do. However, typescript only complains about the second one. Why is the second type invalid, but the first isn't?

// this works
type foo = {
  [key in 'xxx']: number
}

// this does not
type bar = {
  xxx: number
  [key in 'xxx']: number
}

Here are the compiler messages:

A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.ts(1170)
A computed property name must be of type 'string', 'number', 'symbol', or 'any'.ts(2464)
The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter.ts(2361)

See the code in action in the typescript playground.

Upvotes: 1

Views: 3261

Answers (1)

Oblosys
Oblosys

Reputation: 15116

The first definition is a mapped type (doc), which binds key, so you can use it in the right-hand side, e.g.:

type foo = {
  [key in 'xxx']: key
}

You cannot add properties to mapped types though. For example, for

type foo = {
  [key in 'xxx']: key
   xxx: number
}

TypeScript will show an error about an expected } at the position of xxx.

On the other hand,

type bar = {
  xxx: number
  [key in 'xxx']: number
}

is a regular type literal, in which [key in 'xxx']: number is a computed property, for which the restrictions mentioned in the first two error messages hold.

The third error message comes from TypeScript interpreting in as the regular expression-level in. You can see the same error here:

const error = key in 'xxx'

(and if you hover over key in your second example, you'll also see a Cannot find name 'key'. error)

Upvotes: 2

Related Questions