簡體   English   中英

Typescript - 實現泛型類型的類實例

[英]Typescript - Class instance which implements generic type

我有一個使用通用接口創建類的函數。 實例的屬性由該泛型的參數設置,如下所示:

const ClassFactory = <T>() => {

    class MyClass {
        constructor(data: T) {
            for (const key in data) {
                if (!data.hasOwnProperty(key)) { continue; }
                (this as any)[key] = data[key];
            }
        }

        // other methods can be here
    }

    return MyClass;
}

const GeneratedClass = ClassFactory<{ id: number }>();

const myInstance = new GeneratedClass({ id: 1 });

console.log((myInstance as any).id); // logs 1

這按預期運行,但是有兩個問題

  1. myInstance沒有 T 的鍵 - 我希望myInstance.id是一個數字
  2. 我必須在構造函數中將其強制轉換this as any以通過給定數據分配值

為了解決第一個問題,我嘗試了從其他帖子中看到的各種方法,包括class MyClass implements T ,但它們都導致相同的錯誤: A class can only implement an object type or intersection of object types with statically known members.ts(2422) 我明白為什么會發生這種情況,但是因為在定義類時T是已知的,有沒有辦法讓它起作用?

如果我在public data: T屬性中有public data: T ,則正確鍵入myInstance.data.id 所以我的問題是,這可以通過跳過.data部分來完成嗎?

提前致謝

受喬納斯·威爾姆斯 (Jonas Wilms) 評論的啟發,即使該類具有方法/靜態,我也可以通過返回來使其工作

return MyClass as (new (data: T) => T & InstanceType<typeof MyClass>) & typeof MyClass;

像這樣,以下所有內容都按預期輸入和運行

const myInstance = new GeneratedClass({ id: 1 });

console.log(myInstance.id, GeneratedClass.someStatic(), myInstance.someMethod());

但是,如果在類方法中使用new MyClass() ,這將無法正常工作。

它工作的一種解決方法是創建一個靜態的,它返回一個具有正確類型的實例

        // inside the class
        public static build(data: T): T & InstanceType<typeof MyClass> {
            return new MyClass(data) as T & InstanceType<typeof MyClass>;
        }

那么以下是預期的

const myInstance = GeneratedClass.build({ id: 1 });

console.log(myInstance.id, GeneratedClass.someStatic(), myInstance.someMethod());

完整的工作示例

const ClassFactory = <T>() => {
    class MyClass {
        constructor(data: T) {
            for (const key in data) {
                if (!data.hasOwnProperty(key)) { continue; }
                (this as any)[key] = data[key];
            }
        }

        public static build(data: T): T & InstanceType<typeof MyClass> {
            return new MyClass(data) as T & InstanceType<typeof MyClass>;
        }

        public static someStatic() {
            return 2;
        }

        public someMethod() {
            return 3;
        }
    }

    return MyClass as (new (data: T) => T & InstanceType<typeof MyClass>) & typeof MyClass;
}

const GeneratedClass = ClassFactory<{ id: number }>();

const myInstance = new GeneratedClass({ id: 1 });

console.log(myInstance.id, GeneratedClass.someStatic(), myInstance.someMethod());

const myBuiltInstance = GeneratedClass.build({ id: 1 });

console.log(myBuiltInstance.id, GeneratedClass.someStatic(), myBuiltInstance.someMethod());

我剛剛遇到了這個問題,並且能夠通過簡單地放棄new並創建一個通用靜態方法Class.create()來非常優雅地解決它,我在其中實例化並轉換為正確的類型。

interface MyGenericInterface<T = any> {
  getTheThing(): T
}

class MyClass implements MyGenericInterface {
  // Make constructor private to enforce contract
  private constructor(private thing: any) {}

  public getTheThing(): any {
    return this.thing
  }

  static create<TypeOfThing = any>(thing: TypeOfThing) {
    return new MyClass(thing) as MyGenericInterface<TypeOfThing>
  }
}

const stringyInstanceWrong = new MyClass('thing') // Error

const stringyInstance = MyClass.create('thing')
const stringThing: string = stringyInstance.getTheThing()

const numberyInstance = MyClass.create(123)
const numberyThingWrong: string = numberyInstance.getTheThing() // Error
const numberyThing: number = numberyInstance.getTheThing() // Works!

暫無
暫無

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

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