[英]Typescript: trying to use `extends` in generics with `this` in the interface
我正在使用貓鼬,並遇到了一個非常惱人的打字稿問題,我不明白。 我已經解決了問題並簡化了它。
假設函數model
創建了Model
s
interface Model<T extends Document> {}
function model<T extends Document>(): Model<T> {
return {} as Model<T>;
}
我在class
使用此函數如下:
class Collection<T extends Data> {
private Model: Model<T>;
constructor() {
this.Model = model<T>();
}
isRecordValid(record: T): boolean {
return record.created < new Date();
}
}
它是T extends Data
因為我需要訪問created
屬性。 要完成該示例, Document
和Data
界面如下所示
interface Document {
increment(): this;
}
interface Data extends Document {
created: Date;
}
這個問題在Webstorm中已經可見(紅色擺動下划線):
現在,當我編譯這段代碼
$> tsc test.ts
我收到以下錯誤:
test.ts(39,28): error TS2344: Type 'T' does not satisfy the constraint 'Document'.
Type 'Data' is not assignable to type 'Document'.
Types of property 'increment' are incompatible.
Type '() => Data' is not assignable to type '() => T'.
Type 'Data' is not assignable to type 'T'.
這個錯誤是由行increment(): this
引起的increment(): this
或只是this
。 如果刪除該行或替換this
與Document
的問題已經一去不復返了。
在最初的問題中, Document
, model
和Model
來自mongoose,但Collection
是我的。 任何建議問題可能是什么?
該T
在Collection<T extends Data>
類是不一樣的T
在Model<T>()
接口。
問題與接口本身的細節無關 - 問題是,為了能夠擁有Model<TDocument>
類型的對象, TDocument
必須實現Document
接口。 您對Collection
類中的T
沒有這樣的約束(相反,它僅限於實現Data
接口)。
你可以做這樣的事情,以確保T
您的收藏被限制為同時實現Data
和Document
接口:
interface Model<T extends Document> {}
function model<T extends Document>(): Model<T> {
return {} as Model<T>;
}
interface DataAndDoucment extends Data, Document {
}
class Collection<T extends DataAndDoucment> {
private Model: Model<T>;
}
如果您按如下所示重寫Document
類,這相當於返回類型為this
,則錯誤消息會變得更加清晰。
interface Document<U extends Document<U>> {
increment(): U;
}
interface Data extends Document<Data> {
created: Date;
}
interface Model<T extends Document<T>> {}
function model<T extends Document<T>>(): Model<T> {
return {} as Model<T>;
}
class Collection<T extends Data> {
private Model: Model<T>;
constructor() {
this.Model = model<T>();
}
isRecordValid(record: T): boolean {
return record.created < new Date();
}
}
現在,在Model<T>
兩個定義中,您將得到錯誤:
Type 'T' does not satisfy the constraint 'Document<T>'.
Type 'Data' is not assignable to type 'Document<T>'.
Types of property 'increment' are incompatible.
Type '() => Data' is not assignable to type '() => T'.
Type 'Data' is not assignable to type 'T'.
類型檢查器的錯誤跟蹤非常清楚。 如您所見,它試圖斷言Data
是Document<T>
的子類型,為此,它要求Data
是T
的子類型。
修復它的一種方法是使Data
通用,如下所示:
interface Data<T extends Data<T>> extends Document<T> {
created: Date;
}
然后將集合類定義為
class Collection<T extends Data<T>> {
...
}
更新:
我忽略了Document
類型無法更改的事實。 正如Jeanluca本人的評論中所建議的,我們可以通過使用交集類型來解決這個問題:
interface Data {
created: Date;
}
class Collection<T extends Data & Document>
使用此解決方案,我們不再需要Data
和Document
之間的繼承。 由於TypeScript具有結構類型系統,因此T extends Data & Document
的新定義T extends Data & Document
意味着T
應該具有Data
和Document
的屬性,即increment
和created
方法,它滿足model<T extends Document>()
的類型約束。 對於結構類型系統,我們不需要顯式使用extends
,只需具有相同的屬性就足夠了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.