是否可以在自己的扩展约束中使用泛型类型参数



我想在它自己的约束中使用泛型类型参数。这在打字中是可能的吗?

我的代码在这里:

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钩子配置为调用log钩子。为了实现这一点,我试图将并集类型作为泛型参数传递给"FunctionWithThis"类型:

FunctionWithThis<TContext & THooks>

但不幸的是,它并没有给我想要的:我仍然有智能感知上下文,因为我的钩子不可用。当泛型参数用作自身的约束时,它似乎被解析为unknown

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

事实上,我有更复杂的计划:我想为configure函数和回调添加一个更通用的参数,也希望能够从钩子调用回调,反之亦然。所以它看起来是这样的:THooks extends Record<string, FunctionWithThis<TContext & THooks & TCallbacks>>>,其中TCallbacks是继THooks之后的一个新的通用参数

您的特定问题很难用泛型来解决。幸运的是,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();

我还没有研究如何实现您更复杂的计划,但我想确保您在问题中的代码上有一条前进的道路。

游乐场链接到代码

最新更新