簡體   English   中英

打字稿參考擴展類

[英]Typescript reference extended class

我需要引用一個擴展了我的基類的類,而在弄清楚它時遇到了很多麻煩。 我不確定如何解釋它,所以我做了一個演示代碼:

interface BaseAttributes {
    id: string;
}

interface Relation {
    field: string;
    class: typeof One;
}

    class One<A extends BaseAttributes> {
    private relations: Relation[];
    private attr: A;

    constructor(attr: A) {
        this.attr = attr;

        this.relations = (this.constructor as typeof One).getRelations();
    }

    static getRelations(): Relation[] {
        return [];
    }

    static getOne() {
        // Some data fetching here
        const data: TwoAttributes = {
            id: '123',
            label: 'test',
        };

        return new this(data);
    }

    doRelations() {
        return this.relations.map((relation: Relation) => {
            return relation.class.getOne();
        });
    }
}

interface TwoAttributes extends BaseAttributes{
    label: string;
}

class Two extends One<TwoAttributes> {
    static getRelations(): Relation[] {
        return [
            {
                field: 'test',
                class: Three,
            },
        ];
    }
}

interface ThreeAttributes extends BaseAttributes{
    image: string;
}

class Three extends One<ThreeAttributes> {
}

基本上,“一個”是一類,它具有一些屬性和關系。 這些關系可以引用其他“一個”類或擴展它的類。 問題是在類“ Two”中-實現getRelations-我得到

Type '{ field: string; class: typeof Three; }[]' is not assignable to type 'Relation[]'.
  Type '{ field: string; class: typeof Three; }' is not assignable to type 'Relation'.
    Types of property 'class' are incompatible.
      Type 'typeof Three' is not assignable to type 'typeof One'.
        Types of parameters 'attr' and 'attr' are incompatible.
          Type 'A' is not assignable to type 'ThreeAttributes'.
            Type 'BaseAttributes' is not assignable to type 'ThreeAttributes'.
              Property 'image' is missing in type 'BaseAttributes'.

我試圖弄亂使用'typeof'而不使用它的各種變化,但是在Relation中,我需要它來引用類本身。

我也能夠找到同樣問題的問題,但從未得到回答。 鏈接到SO問題

由於值One是泛型類的構造函數,因此其類型typeof One類似於:

type TypeofOne = {
    new <A extends BaseAttributes>(attr: A): One<A>;
    getRelations(): Relation[];
}

(您可以通過注意以下代碼沒有錯誤來驗證這些類型基本相同:

type Same<T extends U, U extends V, V = T> = true;
declare const checkTypeofOne: Same<typeof One, TypeofOne>;

在這種情況下,編譯器會看到typeof OneTypeofOne彼此相互擴展……這幾乎是“同一類型”。)

無論如何,該簽名意味着typeof one是一個構造函數,該構造函數接受通用類型A的參數並返回One<A> 但是Three這樣做。 它僅接受類型ThreeAttributes的參數,並產生One<ThreeAttributes> 因此,您不能在期望TypeofOne地方傳遞Three

因此,也許您真的不希望將Relationclass屬性限制為TypeofOne


也許您真的想說像這樣的東西:“ Relationclass屬性可以是為某個A生成One<A>某個實例的任何構造函數”。 從技術上講,這需要存在類型進行正確編碼,而TypeScript沒有這些 但也許您會滿意:“ Relationclass屬性是一個生成One<any>的構造函數”。 就像是:

type TypeofAnyOne = {
    new(attr: any): One<any>;
    getRelations(): Relation[];
}

在這種情況下,您可以看到TypeofAnyOne不一定是通用構造函數。 它將匹配一個接受any參數並生成One<any>的構造函數。 警告:無論何時使用任何類型 ,都不是完全安全的類型...在這種情況下, TypeofAnyOne可能會匹配接受string並產生One<number>的構造函數,這甚至是不可能的,因為stringnumber都不匹配BaseAttributes

因此,如果將Relation['class']更改為TypeofAnyOne而不是TypeofOne ,它將正常工作:

interface Relation {
    field: string;
    class: TypeofAnyOne; // okay now
}

這可能對您來說已經足夠了,這取決於您要對Relation數組實際執行的操作。 無論如何,希望能幫助您找到有用的方向。 祝好運!

即使接受的答案提供了解決方案,我仍然可以使用另一種方法解決該問題,該方法擺脫了代碼重復,但引入了另一種丑陋的東西。

而不是使用

static getRelations(): Relation[] {
    return [
        {
            field: 'test',
            class: Three,
        },
    ];
}

我能夠使它像這樣工作:

static getRelations(): Relation[] {
    return [
        {
            field: 'test',
            class: Three as typeof One,
        },
    ];
}

很好,因為它允許我使用

interface Relation {
    field: string;
    class: typeof One;
}

並仍然獲得One定義的所有方法。 as仍然會產生奇怪的代碼,尤其是在存在更多關系的情況下,但總的來說,我更喜歡它。

暫無
暫無

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

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