typescript - 如何修复具有多个功能的接口的“没有重载匹配此调用”
问题描述
这是我正在努力的代码:
const enum labelKey {
RATING = 'asset.ratingPercentage',
EPISODE_TITLE = 'episode.title.count.short',
EPISODE_SERIES_TITLE = 'episode.title.series.count.short',
}
interface GetLabel {
(key: labelKey.RATING, options: { rating: string }): string;
(
key: labelKey.EPISODE_TITLE,
options: { episodeNumber: number; seasonNumber: number; episodeTitle: string },
): string;
(
key: labelKey.EPISODE_SERIES_TITLE,
options: { episodeNumber: number; seasonNumber: number; seriesName: string },
): string;
(key: string): string;
}
const getLabel: GetLabel = (key: string, options?: { [key: string]: unknown }) => {
return '';
};
type Label = {
key: labelKey.RATING;
options: { rating: string };
} | {
key: labelKey.EPISODE_TITLE;
options: { episodeNumber: number; seasonNumber: number; episodeTitle: string };
} | {
key: labelKey.EPISODE_SERIES_TITLE;
options: { episodeNumber: number; seasonNumber: number; seriesName: string };
};
function createLabel(someCondition: boolean): Label {
if (someCondition) {
return {
key: labelKey.RATING,
options: { rating: '5' },
};
}
else {
return {
key: labelKey.EPISODE_TITLE,
options: { episodeNumber: 1, seasonNumber: 2, episodeTitle: 'Hello' },
};
}
}
const label = createLabel(false);
getLabel(label.key, label.options);
我什至添加了一个labelKey
枚举(我认为这不是必需的)来向 TypeScript 提供提示,但getLabel
仍然不起作用。
关于如何实现这一点的任何想法?
这里是游乐场。
解决方案
问题的根源是您label.key
在调用getLabel
. 所以前三个重载都不能匹配,因为它们都需要特定的键类型。但是你也不能匹配第四个string
重载,因为这个重载(key: string): string;
要求你不传递第二个参数。
解决方案1:getLabel
让我们添加一个重载,我们知道我们有一个labelKey
但不知道是哪一个。所以我们应该接受options
任何重载,而不要求选项类型与键类型匹配。然后作为最后的手段,您可以添加另一个接受string
任何options
对象的重载。
interface GetLabel {
...exisiting overloads 1-3...
(key: Label['key'], options: Label['options']): string;
(key: string, options: Record<string, any>): string;
}
解决方案2:createLabel
但是我们也可以从createLabel
函数中解决这个问题。目前 Typescript 不知道Label
这个函数返回的是哪种类型。但是我们应该能够根据我们调用函数Label
的值来知道我们将得到哪个。someCondition
所以我们实际上可以在这里添加重载。as const
注意:当您有明确的返回类型时,您实际上并不需要。
// helper function to get a member of the `Label` union
type LabelByKey<K extends labelKey> = Extract<Label, {key: K}>
function createLabel(someCondition: true): LabelByKey<labelKey.RATING>;
function createLabel(someCondition: false): LabelByKey<labelKey.EPISODE_TITLE>;
function createLabel(someCondition: boolean): Label {
if (someCondition) {
return {
key: labelKey.RATING,
options: { rating: '5' },
}
}
else {
return {
key: labelKey.EPISODE_TITLE,
options: { episodeNumber: 1, seasonNumber: 2, episodeTitle: 'Hello' },
}
}
}
现在,当你打电话时,createLabel(false)
你知道你得到一个标签,其类型如下:
const label: {
key: labelKey.EPISODE_TITLE;
options: {
episodeNumber: number;
seasonNumber: number;
episodeTitle: string;
};
}
我们不需要那些额外的重载,因为现在我们可以将第二个重载与key: labelKey.EPISODE_TITLE
.
解决方案 3:泛型
您需要将 alabelKey
与其匹配的信息options
已在Label
联合中可用。所以你不需要在重载中再次输入它。我们可以使用泛型函数而不是重载函数,并使用相同的LabelByKey
辅助类型。
type LabelByKey<K extends labelKey> = Extract<Label, {key: K}>
const getLabel = <K extends labelKey>(
key: K,
options: LabelByKey<K>['options']
) => {
return '';
};
推荐阅读
- python - AttributeError:找不到 PyAudio;检查安装(语音识别)
- python - 我使用 Paramiko 的 Python 脚本在 IDE (PyCharm) 和命令行中完美运行,但不能在 AWS Lambda 上运行
- node.js - 如何获取通过请求连接的用户的本地IP地址 - Nodejs
- android - 共享元素过渡:过渡闪烁,因为目标片段具有嵌套的滚动视图
- javascript - 根据 Parent 节点 id 或 Umbraco 中页面的当前 id 搜索内容
- selenium-webdriver - 自动打开太多 Edge 实例,并显示“错误:file_io_win.cc(180)] CreateFile settings.dat:访问被拒绝。(0x5)”
- loops - 循环遍历未知属性的 Grails 对象的所有字段
- javascript - How to send javascript object to node server
- spring - 如何为 Spring Boot bean 设置默认 Mockito 答案或如何为 Spring Bean 设置代理?
- javascript - Validate.js 忽略其他规则