在定义中,仅当泛型类型是数组时,我才需要特定的方法签名
In definitions, I need a specific method signature only if generic type is an array
这里是 Knockout 的 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[]
.
仅当 T
是一个数组并且能够提取基础类型时,我如何才能包含 arrayChange
事件签名?
您可以使用条件类型从数组中提取项目。要将数组重载的可用性限制为仅当 T
类型是数组时,我们可以为 this
参数添加类型注释。仅当调用目标符合 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
这里是 Knockout 的 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[]
.
仅当 T
是一个数组并且能够提取基础类型时,我如何才能包含 arrayChange
事件签名?
您可以使用条件类型从数组中提取项目。要将数组重载的可用性限制为仅当 T
类型是数组时,我们可以为 this
参数添加类型注释。仅当调用目标符合 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