javascript - 如何利用有区别的联合来推断函数的返回类型
问题描述
鉴于下面的类型、接口和 getData 函数,我试图找到一种利用可区分联合的方法,以便 TS 编译器可以将返回类型缩小getData(source: DOSources)
到关联的DOTypes
// Expected behavior
const result = getData("dataObjectA");
// result.data should be a string but in this case the TS compiler will complain
// that data does not have the toLowerCase() function
result.data.toLowerCase();
示例代码
interface DataObjectA {
source: "dataObjectA";
data: string;
}
interface DataObjectB {
source: "dataObjectB";
data: number;
}
type DOTypes = DataObjectA | DataObjectB
type DOSources = DOTypes["source"];
async function getData(source: DOSources) {
const response = await fetch(`https://some-random-endpoint/`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
switch (source) {
case "dataObjectA":
return await response.json() as DataObjectA;
case "dataObjectB":
return await response.json() as DataObjectB;
}
}
解决方案
您确实可以让编译器根据可区分联合和参数类型计算所需的getData()
返回DOTypes
类型source
。您可以创建getData()
一个泛型函数,其类型参数K extends DOSources
是参数的类型source
。例如:
async function getData<K extends DOSources>(source: K) {
const response = await fetch(`https://some-random-endpoint/`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
return await response.json() as Extract<DOTypes, { source: K }>
}
要找到与之关联的可区分联合的成员,DOTypes
我们K
可以使用实用程序类型。 从属性属于可分配给 的类型的所有联合成员中进行选择。Extract
Extract<DOTypes, {source: K}>
DOTypes
source
K
请注意,我们必须断言该函数返回(Promise
对应于)此类型的值;编译器无法验证这一点。
让我们测试一下:
const resultA = await getData("dataObjectA"); // const result: DataObjectA
resultA.data.toLowerCase();
const resultB = await getData("dataObjectB"); // const result: DataObjectB
resultB.data.toFixed();
看起来不错。每个结果都缩小到预期的类型。如果你加入一个工会,你只会得到一个工会getData()
:
const resultAOrB = await getData(Math.random() < 0.5 ? "dataObjectA" : "dataObjectB");
// const resultAOrB: DataObjectA | DataObjectB
推荐阅读
- android - 使用导航架构组件时后退按钮不起作用
- maven - GoogleCloudPlatform / Java 入门 - 基本应用程序失败
- linux - 目前是否可以在 Linux 上使用带有 Core 3.1 的伪 tty
- c++ - 为什么我不能将引用作为 std::async 的函数参数传递
- core-location - CLAccuracyAuthorization 是否影响 CLCircularRegions 或 Beacon Regions?
- swift - 验证字符串是否包含特定单词
- pandas - Pyspark EMR Notebook - 无法将文件保存到 EMR 环境
- kotlin - Apollo Federation 无法在 docker-compose 中运行连接:无法加载服务定义...原因:连接 ECONNREFUSED 127.0.0.1:80
- google-cloud-platform - 我可以在 GCP 角色定义中使用通配符吗?
- python - 如何修复错误“TypeError:无法腌制时间对象”?