can you solve this typescript error quickly

1 minute read

type User = {
  name: string
  age?: number
  active?: boolean
}

type UserArray = Array<User | null>

function activateUsers(users: UserArray): UserArray {
  return users.map((user) => ({
    ...user,
    active: true,
  }))
}

Looks all good? But if you test the code above, it will give you a lint error:

Type '{ active: true; name?: string | undefined; age?: number | undefined; }[]' is not assignable to type 'UserArray'.
  Type '{ active: true; name?: string | undefined; age?: number | undefined; }' is not assignable to type 'User'.
    Types of property 'name' are incompatible.
      Type 'string | undefined' is not assignable to type 'string'.
        Type 'undefined' is not assignable to type 'string'.typescript(2322)

Why is the error? Please note one of properties of User: name is not nullable. The spread operation, ...user, creates an intermediate type { active: true; name?: string | undefined; age?: number | undefined; }, name is nullable, which is not compatible to User | null, so it cannot be mapped to build an array of User | null.

How to solve the error? There’re a few ways.

  • 1: remove the nullable element

As the element of array is nullable, spread operation will create an intermediate type of which every property is nullable. Yes, that makes sense. Properties of a nullable value of course should still be nullable. So one simple way to fix the error is just to make the element of array not nullable: type UserArray = Array<User>

  • 2: Make all User’s properties nullable

Either change the name property of User to be nullable name?: string, or use Partial: type UserArray = Array<Partial<User> | null>

  • 3: Add null checking at runtime
  return users.map((user) =>
    user ? { ...user, active: true } : null
  )
  • 4: as operator helps as well, but it’s not recommended due to lack of type-safe
  return users.map(
    (user) =>
      ({
        ...user,
        active: true,
      } as User)
  );