Typescript - 交叉类型中的冲突方法签名

Typescript - conflicting method signatures in intersection type

我使用 FeathersJS(很棒)但不幸的是,它不是用 TypeScript 编写的,因此必须单独编写和维护类型。

Here 是打字文件。其中,有一个 Service<T> 类型,看起来像:

export type Service<T> = ServiceOverloads<T> & ServiceAddons<T> & ServiceMethods<T>;

ServiceOverloads<T> 看起来像:

export interface ServiceOverloads<T> {
    create(data: Array<Partial<T>>, params?: Params): Promise<T[]>;

    create(data: Partial<T>, params?: Params): Promise<T>;

    patch(id: NullableId, data: Pick<T, keyof T>, params?: Params): Promise<T>;
}

ServiceMethods<T> 看起来像:

export interface ServiceMethods<T> {
    find(params?: Params): Promise<T[] | Paginated<T>>;

    get(id: Id, params?: Params): Promise<T>;

    create(data: Partial<T> | Array<Partial<T>>, params?: Params): Promise<T | T[]>;

    update(id: NullableId, data: T, params?: Params): Promise<T>;

    patch(id: NullableId, data: Partial<T>, params?: Params): Promise<T>;

    remove(id: NullableId, params?: Params): Promise<T>;
}

如您所见,createpatch 方法应该会发生冲突,因为它们生成相同的 JavaScript.

为什么类型别名 Service<T> 可以编译,但在尝试实现时由于方法冲突而失败?如果我完全从每个接口复制方法并提供一个存根实现,那应该行得通吗?

在 TypeScript 中,intersection of types with function signatures corresponds to overloading those functions. From the relevant GitHub issue introducing intersection types:

Call and Construct Signatures

If A has a signature F and B has a signature G, then A & B has signatures F and G in that order (the order of signatures matter for purposes of overload resolution). Except for the order of signatures, the types A & B and B & A are equivalent.

在您的情况下,ServiceOverloads<T> & ServiceMethods<T> 实际上是

{
    create(data: Array<Partial<T>>, params?: Params): Promise<T[]>; 
    create(data: Partial<T>, params?: Params): Promise<T>;
    create(data: Partial<T> | Array<Partial<T>>, params?: Params): Promise<T | T[]>;

    patch(id: NullableId, data: Pick<T, keyof T>, params?: Params): Promise<T>;
    patch(id: NullableId, data: Partial<T>, params?: Params): Promise<T>;

    find(params?: Params): Promise<T[] | Paginated<T>>;

    get(id: Id, params?: Params): Promise<T>;

    update(id: NullableId, data: T, params?: Params): Promise<T>;

    remove(id: NullableId, params?: Params): Promise<T>;
}

因此您需要在 create()patch() 是重载方法而不是单签名方法的地方实现它。这是一个示例:

class ServiceImpl<T> {
  create(data: Array<Partial<T>>, params?: Params): Promise<T[]>; 
  create(data: Partial<T>, params?: Params): Promise<T>;
  create(data: Partial<T> | Array<Partial<T>>, params?: Params): Promise<T | T[]>;
  create(data: Partial<T> | Array<Partial<T>>, params?: Params) : Promise<T> | Promise<T[]> {
    return null!;  // impl
  }

  patch(id: NullableId, data: Pick<T, keyof T>, params?: Params): Promise<T>;
  patch(id: NullableId, data: Partial<T>, params?: Params): Promise<T>;
  patch(id: NullableId, data: Pick<T, keyof T> | Partial<T>, params?: Params): Promise<T> {
    return null!; // impl
  }

  // other methods
}

function getService<T>(): Service<T> {
  return new ServiceImpl<T>(); // okay
}

希望对您有所帮助;祝你好运!