簡體   English   中英

此重載簽名與其使用擴展類的實現簽名不兼容

[英]This overload signature is not compatible with its implementation signature using extended classes

我不確定這是 typescript 錯誤還是我做錯了什么。 我正在創建一個生成代碼的插件。 生成后我得到錯誤This overload signature is not compatible with its implementation signature

下面是最小的可重現示例。 當我將任何變量添加到任何擴展類時,似乎會出現錯誤。 在這種情況下,如果您刪除protected anything = 'test'; 錯誤會自行消除。

abstract class GraphtonBaseReturnTypeBuilder {

    public withRelated(relatedType: string, buildFields: (r: GraphtonBaseReturnTypeBuilder) => void): this {
        return this;
    }
}

type UserReturnTypeObjectField = "posts"|"friends";

class UserReturnTypeBuilder extends GraphtonBaseReturnTypeBuilder {
    protected anything = 'test';
    
    public withRelated(relatedType: "posts", buildFields: (r: PostReturnTypeBuilder) => void): this;
    //     ~~~~~~~~~~~ This overload signature is not compatible with its implementation signature
    public withRelated(relatedType: "friends", buildFields: (r: UserReturnTypeBuilder) => void): this;
    public withRelated(relatedType: UserReturnTypeObjectField, buildFields: (r: GraphtonBaseReturnTypeBuilder) => void): this {
        return super.withRelated(relatedType, buildFields);
    }
}

type PostReturnTypeObjectField = "author"|"repatedPosts";

class PostReturnTypeBuilder extends GraphtonBaseReturnTypeBuilder {

    public withRelated(relatedType: "author", buildFields: (r: UserReturnTypeBuilder) => void): this;
    //     ~~~~~~~~~~~ This overload signature is not compatible with its implementation signature
    public withRelated(relatedType: "repatedPosts", buildFields: (r: PostReturnTypeBuilder) => void): this;
    public withRelated(relatedType: PostReturnTypeObjectField, buildFields: (r: GraphtonBaseReturnTypeBuilder) => void): this {
        return super.withRelated(relatedType, buildFields);
    }
}


完整文件在 github: https://github.com/GraphtonLib/Graphton/blob/main/example/graphton.generated.ts

Er 錯誤行是第 229 行和第 259 行

完整錯誤:

example/graphton.generated.ts:229:12 - error TS2394: This overload signature is not compatible with its implementation signature.

     public withRelated(relatedType: "posts", buildFields: (r: PostReturnTypeBuilder) => void): this;
               ~~~~~~~~~~~

  example/graphton.generated.ts:231:12
    231     public withRelated(relatedType: UserReturnTypeObjectField, buildFields: (r: GraphtonBaseReturnTypeBuilder) => void): this {
                   ~~~~~~~~~~~
    The implementation signature is declared here.

example/graphton.generated.ts:259:12 - error TS2394: This overload signature is not compatible with its implementation signature.

259     public withRelated(relatedType: "author", buildFields: (r: UserReturnTypeBuilder) => void): this;
               ~~~~~~~~~~~

  example/graphton.generated.ts:261:12
    261     public withRelated(relatedType: PostReturnTypeObjectField, buildFields: (r: GraphtonBaseReturnTypeBuilder) => void): this {
                   ~~~~~~~~~~~
    The implementation signature is declared here.

您嘗試做的主要問題是它不是類型安全的。 這個超類

abstract class GraphtonBaseReturnTypeBuilder {    
    public withRelated(
      relatedType: string, 
      buildFields: (r: GraphtonBaseReturnTypeBuilder) => void
    ): this {
        return this;
    }
}

表示GraphtonBaseReturnTypeBuilder有一個withRelated()方法,其第一個參數是調用者想要傳入的任何string ,第二個參數是回調 function 必須接受調用者想要傳入的任何GraphtonBaseReturnTypeBuilder 。因此,例如,以下一定沒問題:

function process(g: GraphtonBaseReturnTypeBuilder) {
    g.withRelated("randomString", g => console.log(g)); // okay
}

當您聲明class UserReturnTypeBuilder extends GraphtonBaseReturnTypeBuilder時,類型安全要求UserReturnTypeBuilder可以完成GraphtonBaseReturnTypeBuilder可以做的所有事情......並且您可以在需要GraphtonBaseReturnTypeBuilder UserReturnTypeBuilder 這被稱為可替代性

這意味着以下內容也必須沒問題:

process(new UserReturnTypeBuilder()); // also okay

因此,如果UserReturnTypeBuilder覆蓋withRelated()方法,唯一安全的方法是至少接受它覆蓋的方法接受的 arguments。 如果relatedType可以是超類中的任何string ,最好至少是子類中的任何string 它可以接受更多的東西(例如, string | numberunknown ),但它不能安全地接受更少的東西(例如,只是"posts""friends" )。


但是編譯器確實讓您以這種方式不安全; 您可以使UserReturnTypeBuilderwithRelated方法與GraphtonBaseReturnTypeBuilder中的相同方法不兼容,只要不兼容是縮小的。 這被稱為方法參數雙變量,即使它不安全,它也足夠有用,值得允許:

class UserReturnTypeBuilder extends GraphtonBaseReturnTypeBuilder {
  protected anything = 'test';

  public withRelated(
    relatedType: "posts", 
    buildFields: (r: PostReturnTypeBuilder) => void
  ): this;
  public withRelated(
    relatedType: "friends", 
    buildFields: (r: UserReturnTypeBuilder) => void
  ): this;

  public withRelated(
    relatedType: UserReturnTypeObjectField, 
    buildFields: (r: any) => void
  ): this {
      return super.withRelated(relatedType, buildFields);
  }
}

但請注意,當您實現重載withRelated()時,您需要使實現簽名與調用簽名兼容。 而且由於調用簽名接受(r: PostReturnTypeBuilder) => void(r: UserReturnTypeBuilder) => void ,因此實現也必須接受這些...至少與((r: PostReturnTypeBuilder) => void) | ((r: UserReturnTypeBuilder) => void)一樣寬((r: PostReturnTypeBuilder) => void) | ((r: UserReturnTypeBuilder) => void) ((r: PostReturnTypeBuilder) => void) | ((r: UserReturnTypeBuilder) => void)

但是您寫了(r: GraphtonBaseReturnTypeBuilder) => void) ,這是不兼容的。 如果我知道你給我一個接受 PostReturnTypeBuilder 的PostReturnTypeBuilder或接受 UserReturnTypeBuilder 的UserReturnTypeBuilder ,我不能突然假設GraphtonBaseReturnTypeBuilder無論如何都會接受。 這就像邀請客人參加一個聚會,其中一些人可以吃魚( (food: Fish) => void ),而另一些人可以吃雞( (food: Chicken) => void ),然后決定提供牛肉,因為“魚和雞肉都是食物,牛肉也是”( (food: Food) => void )。 這不是它的工作原理(或者至少不安全。也許你的客人都會對牛肉感到滿意,但你從上面的描述中不知道這一點。)

如果您已經不安全並使用雙變量 function 參數,那么您的實現可能應該將buildFields注釋為(r: any) => void

但是,如果您確實關心類型安全,那么您將需要重構您的 class 層次結構。


如果您確實想要安全,那么您不能讓GraphtonBaseReturnTypeBuilder立即接受相關類型的string(r: GraphtonBaseReturnTypeBuilder) => void relatedType buildFields 我的建議是在與子類的相關字段相對應的某些類型參數RF中使其通用,其中鍵是relatedType參數,值是相應的buildFields回調參數類型:

abstract class GraphtonBaseReturnTypeBuilder<RF extends Record<keyof RF, unknown>> {
    public withRelated<K extends keyof RF>(
      relatedType: K, buildFields: (r: RF[K]) => void): this {
        return this;
    }
}

然后,您的子類可以擴展GraphtonBaseReturnTypeBuilder<RF>以獲得為每個子類量身定制的特定RF

interface UserRelatedFields {
    posts: PostReturnTypeBuilder,
    friends: UserReturnTypeBuilder
}
class UserReturnTypeBuilder extends GraphtonBaseReturnTypeBuilder<UserRelatedFields> {

    protected anything = 'test';

    public withRelated<K extends keyof UserRelatedFields>(
      relatedType: K, buildFields: (r: UserRelatedFields[K]) => void) {
        return super.withRelated(relatedType, buildFields); // okay
    }

}

interface PostRelatedFields {
    author: UserReturnTypeBuilder,
    repatedPosts: PostReturnTypeBuilder
}
class PostReturnTypeBuilder extends GraphtonBaseReturnTypeBuilder<PostRelatedFields> {

    public withRelated<K extends keyof PostRelatedFields>(
      relatedType: K, buildFields: (r: PostRelatedFields[K]) => void) {
        return super.withRelated(relatedType, buildFields); // okay
    }
}

這一切都有效,因為您永遠不會有一個未區分的GraphtonBaseReturnTypeBuilder漂浮在周圍; 它總是會是GraphtonBaseReturnTypeBuilder<UserRelatedFields>GraphtonBaseReturnTypeBuilder<PostRelatedFields> ,所以什么都不會接受"randomString"

Playground 代碼鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM