所以最初是为了强制执行约束,所以我只会应用这样的接口
// this is the constraint
interface Topic {
[key: string]: (...args: any[]) => Promise<any>
}
// object that must pass the constraint
const topic: Topic = {
// GOOD: topic methods must conform
async actuate(a: boolean) {}
}
// BAD: type signature broken
topic.actuate(true)
但是问题是topic
的类型被简化为最低公分母,这是约束Topic
—相反,我希望topic
保留其详细类型actuate
所以我发现了这种cr脚的骇客方式,可以兼得两全:
interface Topic {
[key: string]: (...args: any[]) => Promise<any>
}
type TopicConstraint<T extends Topic> = T
const topic = {
// GOOD: topic methods must conform
async actuate(a: boolean) {}
}
// BAD: weird ugly unused type variable constraint hack
// BAD: all topic constraint errors actually land here
type TopicCheck = TopicConstraint<typeof topic>
// GOOD: type signature preserved
topic.actuate(true)
是否有一些更合适的方法可以更优雅地完成此任务?我不知道如何用打字稿表达这种约束情况
但是我还是忍不住觉得有什么特别之处
type TopicConstraint<T extends Topic> = T
这可能是关键...这让我想做非法打字稿之类的事情
// invalid, but i need something in the same spirit
const topic = TopicConstraint<{
async actuate(a: boolean) {}
}>
// invalid, but i need something in the same spirit
const topic: TopicConstraint<@self> = {
async actuate(a: boolean) {}
}
我正在寻找一种我找不到的语法..是否有其他方法?谢谢!
答案 0 :(得分:2)
处理此问题的方法根本不是注释变量,而是让编译器推断其类型。然后,在以后的某个时间,当您在期望Topic
的某个地方使用该变量时,会得到所需的错误那里:
const topic = {
async actuate(a: boolean) { }
};
topic.actuate(true);
const badTopic = {
oops(a: boolean) { }
}
badTopic.oops(true);
// later ...
function topicTaker(t: Topic) {
// do something with a Topic
}
topicTaker(topic); // okay
topicTaker(badTopic); // error!
// ------> ~~~~~~~~
// Property 'oops' is incompatible with index signature.
这可行,在某些用例中,这确实足够了:您实际上并不关心变量的类型是否正确,直到尝试使用它为止。
但是如果此错误检查与对象声明相距太远而对您没有帮助怎么办?
好吧,如果您想尽早发现错误,可以执行我通常做的事情,并创建一个 helper函数:
const asTopic = <T extends Topic>(topic: T) => topic;
此受约束的通用标识函数仅在运行时返回其参数。但是在编译时,将要求topic
可分配给Topic
,而实际上没有扩大到topic
。不必注释变量,只需将它们初始化为helper函数的返回值即可:
const topic = asTopic({
async actuate(a: boolean) { }
});
topic.actuate(true); // okay
const badTopic = asTopic({
oops(a: boolean) { } // error!
// ~~~~
// void is not assignable to type Promise<any>
})
您可以通过两种方式查看asTopic()
:作为替换注释以避免扩展(即使用asTopic()
代替: Topic
),或早期警告,表明您的对象不是所需的类型(即asTopic()
的行为类似于topicTaker()
,您可以在创建站点立即调用它而不是推迟它)。
重新阅读这个问题:这个asTopic()
辅助函数可能就是您在TopicConstraint
上遇到的事情。
答案 1 :(得分:1)
一种选择是使用一个无操作函数,该函数在参数中具有相关的泛型,以便将其约束在适当的位置:
// this is the constraint
interface Topic {
[key: string]: (...args: any[]) => Promise<any>
}
function ensureTopic<T extends Topic>(topic: T){
return topic;
}
// object that must pass the constraint
const topic = ensureTopic({
// GOOD: topic methods must conform
async actuate(a: boolean) {}
})
相关:Use function interface to ensure parameters but infer more specific return type