Typescript:在静态方法中使用子类

2023-12-27

在 TypeScript 中(我使用了操场 https://www.typescriptlang.org/play,版本 4.13) ,当我从一个类继承时,this里面一个static父类的方法似乎引用了继承类:

class Parent{
    static ID = 0
    public id: number

    static create(){
        return new this(this.ID)
    }

    constructor(id: number){
        this.id = id
    }
}

class Child extends Parent{
    static ID = 1
}

let child = Child.create()
console.log(child.id)  // 1

但是,当我想根据子类的类型定义某些行为时,我遇到了问题:

class Parent{
    static create(data: object){
        let instance = new this
        for (let [key, value] of Object.entries(data)){
            this[key] = value
        }
        return instance
    }
}

class Child extends Parent{
    id: number | null = null
}

let child = Child.create({id: 1})
console.log(child.id)

这给了我

元素隐式具有“any”类型,因为类型为“string |”的表达式数量 | “symbol”不能用于索引类型“typeof Parent”。在类型“typeof Parent”上找不到带有“string”类型参数的索引签名。

我试图通过类型转换来解决这个问题key作为子类的键:

class Parent{
    static create(data: object){
        let instance = new this
        for (let [key, value] of Object.entries(data)){
            this[key as keyof this] = value
        }
        return instance
    }
}

class Child extends Parent{
    id: number | null = null
}

let child = Child.create({id: 1})
console.log(child.id)

但这是被禁止的。我明白了

“this”类型仅在类或接口的非静态成员中可用

另外,我得到(在所有情况下)

类型“Parent”上不存在属性“id”。

如何解决我的问题 - 从对象(我在现实场景中从 API 接收)动态填充子类的属性?


您可以通过指定一个来完成此操作this对应于类本身的参数。在静态方法中,this指类本身。

static create<T extends Parent>(this: new (...args: any[]) => T, data: object) {...} 

这里发生的事情是我们说的是this类型,它将引用包含该方法的对象,在这种情况下,无论是哪个类对象create被调用时,可以返回该类的实例类型的子类型。这是通过类型参数完成的T,以及类对象将具有返回一个构造签名的归属T,从而捕获任何派生类的实例类型。

这是完整的工作代码:

class Parent {
    static create<T extends Parent>(this: new (...args: any[]) => T, data: object) {
        let instance = new this;
        for (let [key, value] of Object.entries(data)) {
            instance[key as keyof T] = value;
        }
        return instance;
    }
}

class Child extends Parent {
    id: number | null = null;
}

let child = Child.create({ id: 1 });
console.log(child.id);

游乐场链接 https://www.typescriptlang.org/play?#code/MYGwhgzhAEAKYCcCmA7ALtA3gKGn6EaYaAlsNMMsUgDwAq0SAHmqgCYzzLoB8AFGgAWJCAC5oKJAHdofAHQLEAczHQwKAJ4BtALoBKaAF4e0OgBpobYmHEB7AEYArJMDQGc+T9BBIMJFITqwEhGEtLQQiIA3LheeABmtgiyPhhaANZIGhYAbmAgAK5IOtC28dAA8k4uaHKoaAgkSBB8VkR67rFxnv6BKMEZWWowmRplpiWG0HmFSDHd0AC+XV7IaAUIKNC9RP1zK8vL2KCQMADCwiBsjCzsnIj1WCskbOIoBQC29kjJAD4SBRAIFC7yBMSOqQol2uUwuJCuckoSGofEw21e0AAjEs9DFgLYArYfHIQLYlHxgNC5C9cUA

由于我们已经通过以下方式捕获了派生实例类型T,我们可以细化create通过调整 create 进一步提高类型安全性的方法如下:

static create<T extends Parent>(this: new (...args: any[]) => T, data: Partial<T>) {...}

这阻止我们传递,从而将任意属性分配给由create方法同时提供智能感知。

完整代码:

class Parent {
    static create<T extends Parent>(this: new (...args: any[]) => T, data: Partial<T>) {
        let instance = new this;
        for (let [key, value] of Object.entries(data)) {
            const k = key as keyof T;
            instance[k] = value as T[typeof k];
        }
        return instance;
    }
}

class Child extends Parent {
    id: number | null = null;
}

let child = Child.create({ id: 1 });
console.log(child.id);

游乐场链接 https://www.typescriptlang.org/play?#code/MYGwhgzhAEAKYCcCmA7ALtA3gKGn6EaYaAlsNMMsUgDwAq0SAHmqgCYzzLoB8AFGgAWJCAC5oKJAHdofAHQLEAczHQwKAJ4BtALoBKaAF4e0OgBpobYmHFdSYEPR4Gc+N9BBIMJFIXXAkIwlpaCERAG5cdzwAMwB7BFlPDC0AayQNCwA3BwBXJB1oOJjoAHkAIwArJGA0OVQ0BBIkCD4rIj0XKOi3YDjfDFSg9I01GBHi00ie9x8-FAC0wsNoHJB8sdMtNA0AByRJ1J1pnoBfbvdkNFyEFGg5ogWkE7xz8+xQSBgAYWEQNkYLHYnEQDSwFxIbHEKFyAFtykhEgAfCS5EAgIIw9GRd7JCh-AErX4kf5yShIah8TD3KHQACM0FOekifV8cU8chAcSUfGABLkkOZQA

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Typescript:在静态方法中使用子类 的相关文章

随机推荐