Home > Enterprise >  Typescript reference 'this' type of an object
Typescript reference 'this' type of an object

Time:01-09

Consider the following type:

type UserList = {
  userIds: string[]
  userData: {
    [UserId in UserList['userIds'][number]]: {
      userId: UserId
      username: string
    }
  }
}

with that I want to tell TypeScript compiler two things:

  1. userData keys must exist in userIds
  2. userId field must be equal to the key of the same entry

I feel that I need some kind of this or self keyword instead of UserList

CodePudding user response:

I don't believe it's possible to refer to the exact string values inside userIds without resorting to using a generic type parameter:

type UserList<T extends ReadonlyArray<string>> = {
  userIds: T
  userData: {
    [UserId in T[number]]: {
      userId: UserId
      username: string
    }
  }
}

And your type definition would have to look as follows:

const a: UserList<['hello']> = {
    userIds: ['hello'],
    userData: {
        hello: {
            userId: 'hello',
            username: 'username'
        }
    }
}

If you don't want to specify the user IDs twice (inside the generic parameter and inside the actual UserList variable), you have to use a wrapper function:

function asUserList<T extends ReadonlyArray<string>>(list: UserList<T>) {
  return list;
}

const a = asUserList({
    userIds: ['hello'] as const,
    userData: {
        hello: {
            userId: 'hello',
            username: 'username'
        }
    }
})

If you don't use a generic parameter and instead try to use the this type inside an interface like this:

interface UserList {
  userIds: string[]
  userData: {
    [UserId in this['userIds'][number]]: {
      userId: UserId
      username: string
    }
  }
}

It wouldn't work because this['userIds'] would always resolve to the weak string[] type, not a specific set of strings that would allow you to strongly type userData based on the exact value of userIds.

  • Related