Typescript 引用对象的 ‘this’ 类型

huangapple go评论72阅读模式
英文:

Typescript reference 'this' type of an object

问题

考虑以下类型:

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

有了这个,我想告诉TypeScript编译器两件事:

  1. userData 的键必须存在于 userIds
  2. userId 字段必须等于相同条目的键

我觉得我需要某种 thisself 关键字,而不是 UserList

英文:

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

答案1

得分: 0

我不相信可以在不使用通用类型参数的情况下引用userIds内的确切字符串值,除非使用通用类型参数:

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

并且您的类型定义应该如下所示:

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

如果您不想两次指定用户ID(在通用参数内和实际UserList变量内),您必须使用包装函数:

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

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

如果您不使用通用参数,而是尝试在接口内部使用this类型,如下所示:

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

它将不起作用,因为this['userIds']将始终解析为弱类型string[],而不是允许您根据userIds的确切值强类型userData的特定字符串集合。

英文:

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&lt;T extends ReadonlyArray&lt;string&gt;&gt; = {
  userIds: T
  userData: {
    [UserId in T[number]]: {
      userId: UserId
      username: string
    }
  }
}

And your type definition would have to look as follows:

const a: UserList&lt;[&#39;hello&#39;]&gt; = {
    userIds: [&#39;hello&#39;],
    userData: {
        hello: {
            userId: &#39;hello&#39;,
            username: &#39;username&#39;
        }
    }
}

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&lt;T extends ReadonlyArray&lt;string&gt;&gt;(list: UserList&lt;T&gt;) {
  return list;
}

const a = asUserList({
    userIds: [&#39;hello&#39;] as const,
    userData: {
        hello: {
            userId: &#39;hello&#39;,
            username: &#39;username&#39;
        }
    }
})

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[&#39;userIds&#39;][number]]: {
      userId: UserId
      username: string
    }
  }
}

It wouldn't work because this[&#39;userIds&#39;] 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.

huangapple
  • 本文由 发表于 2023年1月9日 00:01:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/75049251.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定