简体   繁体   English

典型观察者模式的打字稿

[英]Typescript for typical observer pattern

I'm trying to write typescript for a structure like observer pattern and I'm failing to achieve this.我正在尝试为像观察者模式这样的结构编写打字稿,但我没有做到这一点。 I think I'm almost done but for some reason I don't understand why the ts is complaining.我想我快完成了,但出于某种原因,我不明白为什么 ts 抱怨。

type OnChangeListener = (object: object, from: string, to: string) => void
type OnCreateListener = (object: object) => void

type ListenerTypes = {
    onChange: OnChangeListener,
    onCreate: OnCreateListener
}

type Listener<T extends keyof ListenerTypes> = ListenerTypes[T]

type Listeners = {
    onChange: OnChangeListener[],
    onCreate: OnCreateListener[]
}

class SomeClass {
    private listeners: Listeners = {
        onChange: [],
        onCreate: []
    }

    public create(object: object) {
        this.listeners.onCreate.forEach(listener => listener(object))
    }

    public change(object: object, from: string, to: string) {
        this.listeners.onChange.forEach(listener => listener(object, from, to))
    }

    public registerListener<T extends keyof ListenerTypes>(name: T, listener: Listener<T>): void
    {
        this.listeners[name].push(listener) // <-- here is a problem
        /*
Argument of type 'Listener<T>' is not assignable to parameter of type 'OnCreateListener'.
  Type 'OnChangeListener | OnCreateListener' is not assignable to type 'OnCreateListener'.
    Type 'OnChangeListener' is not assignable to type 'OnCreateListener'
        */
    }
}

const someObject = new SomeClass()

someObject.registerListener("onChange", (o, from, to) => {}) // <-- this is ok
someObject.registerListener("onCreate", (o) => {}) // <-- this is ok
someObject.registerListener("onCreate",  (o, from, to) => {}) // <-- this error is ok, as the callback should be different

When I change the Listeners type to当我将 Listeners 类型更改为

type Listeners = {
    onChange: any[],
    onCreate: any[]
}

then register function works ok, but the trigger doesn't shows any type on the listener object in forEach as it's obvious.然后 register 函数可以正常工作,但是触发器没有在 forEach 中的侦听器对象上显示任何类型,因为很明显。 So the option there is casting what I don't like.所以那里的选项是铸造我不喜欢的东西。 What I am doing wrong here?我在这里做错了什么?

If you take a look at the index type examples in the docs, it seems that generically indexing only works when the type of the object being indexed is itself part of the generic context of the function, as opposed to a specific object outside of it.如果您查看文档中的索引类型示例,似乎只有当被索引的对象的类型本身是函数的通用上下文的一部分时,一般索引才有效,而不是它之外的特定对象。

Inside the registerListener function, the type of listener in this.listeners[name].push(listener) is expected to be an intersection of OnChangeListener and OnCreateListener because it doesn't know what whether name will be "onChange" or "onCreate" and will thus only accept function signatures that are applicable to both.registerListener函数中, this.listeners[name].push(listener)listener类型应该是OnChangeListenerOnCreateListener的交集,因为它不知道name"onChange"还是"onCreate"并且因此将只接受适用于两者的函数签名。 Typescript doesn't do the generic index magic unless the object type is generic as well.除非对象类型也是通用的,否则 Typescript 不会执行通用索引魔术。

Since registerListener does properly discriminate the listener signature that should be passed for the given key, I think the best solution is just to tell Typescript that the listener array you're accessing matches the listener passed.由于registerListener确实正确区分了应该为给定键传递的侦听器签名,因此我认为最好的解决方案是告诉 Typescript 您正在访问的侦听器数组与传递的侦听器匹配。


public registerListener<T extends keyof ListenerTypes>(name: T, listener: Listener<T>): void {
    (this.listeners[name] as Listener<T>[]).push(listener);  
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM