是否可以在其自身的扩展约束中使用通用类型参数?

时间:2020-09-29 14:42:36

标签: typescript typescript-generics

我想在其自身的约束中使用泛型类型参数。打字稿根本有可能吗?

我的代码在这里:

hm <- pheatmap(test, silent = TRUE)
hm$gtable$grobs[[5]]$gp$col <- rep(c("black", "red"), each = 10)
leg <- legendGrob(c("Exp1", "Exp2"), nrow = 2, pch = 15, gp = gpar(fontsize = 10, col = c("black", "red")))
hm2 <- arrangeGrob(hm$gtable, leg, ncol = 2, widths = c(5,1))
grid.draw(hm2)

或者在typescript playground

我正在尝试创建一个配置功能,以使用预定义的上下文执行一组功能。 我已经设法创建了一个简单的演示版本,但是现在我希望能够从另一个挂钩中调用挂钩。例如。我想将我的type Config<T> = { context: T; }; type Hooks<T> = { hooks: T; }; type FunctionWithThis<T> = (this: T, ...args: any[]) => any; type RemoveThis<T extends Record<string, FunctionWithThis<any>>> = { [P in keyof T]: T[P] extends (...a: infer A) => infer R ? (...a:A) => R: never } const configure = <TContext extends Object, THooks extends Record<string, FunctionWithThis<TContext & THooks>>> // problem here (config: Config<TContext> & Hooks<THooks>) => { const result = { get data() { return config.context; } }; Object.entries(config.hooks).forEach((action) => { (result as any)[action[0]] = (...args: any[]) => action[1].call(config.context as any, ...args); }); return result as { data: TContext; } & RemoveThis<THooks>; }; const engine = configure({ context: { foo: 12 }, hooks: { log() { console.log(this.foo); // this.foo is typed correctly here but I don't have access to another hooks }, test(str: string) { } } }); 挂钩配置为调用test挂钩。 为了实现这一点,我试图将联合类型作为通用参数传递给“ FunctionWithThis”类型:

log

但是不幸的是,它并没有给我我想要的东西:我仍然对上下文有智能感知,这是因为我的钩子不可用。通用参数用作自身约束时,似乎解析为FunctionWithThis<TContext & THooks>

这是克服这个问题的方法吗?

实际上,我有更复杂的计划:我想为unknown函数和回调添加一个通用参数,并且还希望能够从钩子调用回调,反之亦然。因此它看起来像这样:configure,其中THooks extends Record<string, FunctionWithThis<TContext & THooks & TCallbacks>>>是紧随TCallbacks

之后的新通用参数

1 个答案:

答案 0 :(得分:3)

仅泛型很难解决您的特定问题。幸运的是,TypeScript具有一个称为ThisType的特殊魔术类型函数,该函数在microsoft/TypeScript#14141中实现,该函数允许指定对象文字方法的this上下文。

我希望您输入的代码是这样的:

type ConfigwithHooks<C, H> = {
    context: C;
    hooks: H & ThisType<C & H>; // Type of 'this' in hooks is C & H
};

const configure = <C, H>(config: ConfigwithHooks<C, H>) => {
    const result = {
        get data() { return config.context; }
    };

    Object.entries(config.hooks).forEach((action) => {
        (result as any)[action[0]] = (...args: any[]) => action[1].call(config.context as any, ...args);
    });

    return result as { data: C } & H;
};

我认为这可以按照您想要的方式工作:

const engine = configure({
    context: {
        foo: 12
    },
    hooks: {
        log() {
            console.log(this.foo);
            this.test("hello");
        },
        test(str: string) {
            this.foo - 5;
        }
    }
});
    
/* const engine: {
    data: {
        foo: number;
    };
} & {
    log(): void;
    test(str: string): void;
} */

const data = engine.data;
engine.log();

我还没有研究如何实施更复杂的计划,但是我想确保您对所提出的问题中的代码有所了解。

Playground link to code

相关问题