【问题标题】:Declare an additional member to a method of a class为类的方法声明一个附加成员
【发布时间】:2019-04-09 22:31:04
【问题描述】:

我用打字稿装饰器装饰了一个方法,向该方法添加了一个成员:

export class MyClass {
    @AddMyMember()
    public myMethod(param1:string) {
        // ...
    }
}

所以我应该可以这样使用它:

const myClassInstance = new MyClass();
myClassInstance.myMethod.myMember(); // error of course here, as myMember has not been declared yet...

但我找不到有效声明 myMember 的方法:

export declare interface MyClass {
// Something great here maybe?....
}

【问题讨论】:

标签: typescript typescript-typings strong-typing


【解决方案1】:

合并问题

没有办法声明不同类型的类的成员,声明合并只能添加成员而不改变现有成员的类型。

我们可以做的就是使用交集类型。如果一个交集类型的两个成员具有相同的名称和不同的类型,则该交集上的成员将是两个原始类型的交集。

class _MyClass {
    public constructor (t: string) {

    }
    public myMethod(param1:string) {
    }

    static staticF(){}
}

type ReplaceInstanceType<T extends new(...a: any[])=> any, TNew> = {
    new (... a: (T extends new (...p: infer P) => unknown ? P: [])) : TNew
} & Pick<T, keyof T>

export type MyClass = _MyClass & {
    myMethod: {
        myMember(): void
    }
}


export const MyClass: ReplaceInstanceType<typeof _MyClass, MyClass> = _MyClass as any;

let a = new MyClass("") // can new up
a.myMethod("") // can call myMethod
a.myMethod.myMember(); // can call  myMember
MyClass.staticF

装饰器问题

问题的第二部分是装饰器不能改变它所应用的成员的类型(这是设计使然)。您可以改为使用 HOC 创建类,并传入成员名称列表(使用 keyof 进行编译检查)以添加额外的成员:

type ReplaceInstanceType<T extends new(...a: any[])=> any, TNew> = {
    new (... a: (T extends new (...p: infer P) => unknown ? P: [])) : TNew
} & Pick<T, keyof T>

function addMemebers<T extends new(...a: any[])=> any, K extends keyof InstanceType<T>>(members: K[], cls: T) : ReplaceInstanceType<T, InstanceType<T> & Record<K, {myMember(): void}>>{
    return null as any; // replace with implementation
}
export const MyClass = addMemebers(["myMethod"], class {
    public constructor (t: string) {

    }
    public myMethod(param1:string) {
    }

    static staticF(){}
})


let a = new MyClass("") // can new up
a.myMethod("") // can call myMethod
a.myMethod.myMember(); // can call  myMember
MyClass.staticF

【讨论】:

  • 你的回答很棒而且很清楚,谢谢。关于装饰器,我已经实现了,我只需要类型声明。修改应用了装饰器的成员有一个技巧:您的装饰器可以返回 {可配置:true, get(this:MyClass) { ... } } 其中 MyClass 断言是主机(也可以使用泛型类型)。获得主机实例后,您就可以从装饰器中更改您想要的成员的所有内容:-)
  • @CharlesHETIER 我可能回答的不是很清楚,可以修改运行时JS类,不能改变静态Typescript类型。
猜你喜欢
  • 1970-01-01
  • 2012-06-22
  • 1970-01-01
  • 2021-10-08
  • 2010-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多