代码之家  ›  专栏  ›  技术社区  ›  Michael Best

在定义中,仅当泛型类型是数组时,我才需要特定的方法签名

  •  2
  • Michael Best  · 技术社区  · 7 年前

    这是一个略显简化的敲除定义 subscribable :

    export type SubscriptionCallback<T = any, TTarget = void> = (this: TTarget, val: T) => void;
    
    export interface Subscription {
        dispose(): void;
    }
    
    export interface SubscribableFunctions<T = any> extends Function {
        init<S extends Subscribable<any>>(instance: S): void;
    
        notifySubscribers(valueToWrite?: T, event?: string): void;
    
        // This definition is wrong
        subscribe<TTarget = void>(callback: SubscriptionCallback<Array<ArrayChange<T>>, TTarget>, callbackTarget: TTarget, event: "arrayChange"): Subscription;
    
        subscribe<TTarget = void>(callback: SubscriptionCallback<T, TTarget>, callbackTarget?: TTarget, event?: "change"): Subscription;
        subscribe<X = any, TTarget = void>(callback: SubscriptionCallback<X, TTarget>, callbackTarget: TTarget, event: string): Subscription;
    
        extend(requestedExtenders: ObservableExtenderOptions): this;
        extend<S extends Subscribable<any>>(requestedExtenders: ObservableExtenderOptions): S;
    
        getSubscriptionsCount(event?: string): number;
    }
    
    export interface Subscribable<T = any> extends SubscribableFunctions<T> { }
    
    export interface ArrayChange<T = any> {
        status: "added" | "deleted" | "retained";
        value: T;
        index: number;
        moved?: number;
    }
    

    问题是 arrayChange 这个事件是错误的。首先 arrayChange 事件仅适用于以下情况: T X[] . 然后 ArrayChange 接口需要是 X 类型与否 X[] .

    arrayChange 事件签名仅当 T

    1 回复  |  直到 7 年前
        1
  •  2
  •   Titian Cernicova-Dragomir    7 年前

    可以使用条件类型从数组中提取项。将阵列重载的可用性限制为仅当 T 类型是一个数组,我们可以为 this 参数只有当调用目标符合 这 参数类型。

    export type SubscriptionCallback<T = any, TTarget = void> = (this: TTarget, val: T) => void;
    
    export interface Subscription {
        dispose(): void;
    }
    
    // The conditional type that extracts the array item if T is an array
    type ItemIfArray<T> = T extends Array<infer U> ? U : never;
    
    export interface SubscribableFunctions<T = any> extends Function {
        init<S extends Subscribable<any>>(instance: S): void;
    
        notifySubscribers(valueToWrite?: T, event?: string): void;
    
        // this must be something compatible with  SubscribableFunctions<any[]> which should mean a SubscribableFunctions where T is an array 
        subscribe<TTarget = void>(this: SubscribableFunctions<any[]>, callback: SubscriptionCallback<Array<ArrayChange<ItemIfArray<T>>>, TTarget>, callbackTarget: TTarget, event: "arrayChange"): Subscription;
    
        subscribe<TTarget = void>(callback: SubscriptionCallback<T, TTarget>, callbackTarget?: TTarget, event?: "change"): Subscription;
         // since the last overload has the event of type string it allows invocation with arrayChange so I removed it to get the error below, not 100% sure if keeping this overload is a good idea. 
        //subscribe<X = any, TTarget = void>(callback: SubscriptionCallback<X, TTarget>, callbackTarget: TTarget, event: string): Subscription;
        getSubscriptionsCount(event?: string): number;
    }
    
    export interface Subscribable<T = any> extends SubscribableFunctions<T> { }
    
    export interface ArrayChange<T = any> {
        status: "added" | "deleted" | "retained";
        value: T;
        index: number;
        moved?: number;
    }
    
    let a: Subscribable<number>
    a.subscribe(() => { }, void 0, 'arrayChange') //err overload not available for this type parameter 
    
    
    let ar: Subscribable<number[]>
    ar.subscribe(a => a[0].value.toExponential() , void 0, 'arrayChange') //ok
    
    推荐文章