[英]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
完整錯誤:
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 | number
或unknown
),但它不能安全地接受更少的東西(例如,只是"posts"
或"friends"
)。
但是編譯器確實讓您以這種方式不安全; 您可以使UserReturnTypeBuilder
的withRelated
方法與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"
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.