首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何根据另一个参数中的属性值设置类型?

如何根据另一个参数中的属性值设置类型?
EN

Stack Overflow用户
提问于 2022-01-20 16:30:51
回答 2查看 504关注 0票数 1

如何根据方法中另一个参数的属性值设置类型?相对来说,我是TypeScript的新手。

这就是我试过的:

代码语言:javascript
复制
class SomeClass {
    // constructor, other properties, etc
    listen<K extends keyof ClientEvents>({ event: K }: ClientEvent, listener: (...args: ClientEvents[K]) => any)
}

在这里,ClientEvents看起来像这样:

代码语言:javascript
复制
interface ClientEvents {
    "event-1": [data: number]
    "event-2": [data: number]
    "event-3": [data: any]
}

ClientEvent (no s)看起来如下:

代码语言:javascript
复制
interface ClientEvent {
    event: keyof ClientEvents
    anotherProperty: any // I don't want to share all the properties
}

目前,event字段对event-1进行自动填充,但是函数的第一个参数显示为any类型,但应该是number类型。我如何在不需要更多参数的情况下修复这个问题?

当将data之一从ClientEvents内部更改为string类型时,它将显示为string | number类型。

代码语言:javascript
复制
class SomeClass {
  listen<K extends keyof ClientEvents>({ event: K }: ClientEvent, listener: (...args: ClientEvents[K]) => any): void;
}

interface ClientEvents {
  "event-1": [data: number]
  "event-2": [data: string]
}

interface ClientEvent {
  event: keyof ClientEvents
  anotherProperty: any
}

new SomeClass().listen({ 
  event: "event-1", 
  anotherProperty: 1 
}, (arg) => { 
  arg // type is string | number
})

这是一个操场连接

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-01-20 19:04:41

有关可能的权威答案,请参见解构赋值和类型注释的常见问题条目

您的问题是,K in { event: K }: ClientEvent不是您所认为的那样。在K中,如果您有一个像{ event: K }这样的函数参数,那么您将使用用变量重命名破坏赋值,因此您将将该函数参数的event属性复制到名为event变量中。

代码语言:javascript
复制
function foo({event: K}: ClientEvent) {
  // variable -----> ^
  console.log(K.toUpperCase()); 
  //          ^ <---- see?      
}
foo({event: "event-1", anotherProperty: 123})  // EVENT-1

因为JavaScript支持这一点,所以TypeScript也支持这一点(正如您可以从ClientEvent 类型注释看到的那样),因此调用签名本身只是使用K作为它忽略的虚拟参数名称。

当然,该K不能用作同名类型参数K的推断站点,因为它们是无关的。

您试图使用K作为event属性的类型注释。但这是不支持的。事实上,目前还没有办法将类型注释放在析构对象本身中。微软/打字稿#29526上有一个开放的特性请求,要求采取某种方法(也许.双冒号?但就目前而言,这是不可能的。

如果您想给event属性提供一个类型,则必须在实际的类型注释中在析构对象之后执行该类型:

代码语言:javascript
复制
{ event }: { event: K }

如果您想要保留整个事物需要是一个ClientEvent这一事实,您需要用类似于相交类型的东西来表示这一点。

代码语言:javascript
复制
{ event }: { event: K } & ClientEvent

或者可能通过扩展您的ClientEvent接口,如果看起来更好的话:

代码语言:javascript
复制
interface ClientEventFor<K extends keyof ClientEvents> extends ClientEvent {
  event: K
}

declare class SomeClass {
  listen<K extends keyof ClientEvents>(
    { event }: ClientEventFor<K>,
    listener: (...args: ClientEvents[K]) => any): void;
}

然后事情就会开始对你起作用:

代码语言:javascript
复制
new SomeClass().listen(
  { event: "event-1", anotherProperty: 1 },
  (arg) => { arg.toFixed() } // okay, arg is number here
)

操场链接到代码

票数 1
EN

Stack Overflow用户

发布于 2022-01-20 18:08:04

在接口中使用类型参数的解决方法

代码语言:javascript
复制
export interface ClientEvent<L = keyof ClientEvents> {
    event: L,
    site: string
}

export class SomeClass {
    listen<K extends keyof ClientEvents>({ event }: ClientEvent<K>, listener: (...args: ClientEvents[K]) => any): SomeClass
}

和JavaScript代码:

代码语言:javascript
复制
let a = new Client()
a.listen({
    event: "event-2"
}, (a) => {
    a
})

a是一个字符串,所以它工作得很完美。

操场连接

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70789912

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档