[英]Typescript find in array with different types
I have an array of objects, each object has different type.我有一个对象数组,每个 object 都有不同的类型。 I am using Array.find (or for loop, no difference) to get one of the objects from array.
我正在使用 Array.find(或 for 循环,没有区别)从数组中获取对象之一。 Right now Typescript can not understand what type i am getting from array unless i add additional
|| reportData.type !== "REGIONS"
现在 Typescript 无法理解我从数组中获取的类型,除非我添加额外的
|| reportData.type !== "REGIONS"
|| reportData.type !== "REGIONS"
check. || reportData.type !== "REGIONS"
检查。 Is there any other way to solve it?还有其他方法可以解决吗?
export interface IReportItemFactionStatus {
type: "FACTION_STATUS";
}
export interface IReportItemRegions {
type: "REGIONS";
regions: [];
}
export type IReportItem = IReportItemRegions | IReportItemFactionStatus;
export type IReport = Array<IReportItem>;
// ... code ...
// report has type IReport
const reportData = report.find((d) => {
return d.type === "REGIONS";
});
if (!reportData) {
return [];
}
console.log(reportData.regions); // Typescript error here
But if i add additional check for reportData.type it starts to work fine但是,如果我为 reportData.type 添加额外的检查,它就会开始正常工作
if (!reportData || reportData.type !== "REGIONS") {
return [];
}
console.log(reportData.regions); // No Typescript error here :\
Your structure enforces reportData
to be of type IReportItem
which is : IReportItemRegions
or IReportItemFactionStatus
because it's an element of report
array. 您的结构将
reportData
的类型设置为IReportItem
,它是: IReportItemRegions
或IReportItemFactionStatus
因为它是report
数组的元素。
You want to display property regions
which is only implemented in interface IReportItemRegions
. 您想要显示仅在
IReportItemRegions
接口中实现的属性regions
。 We have no idea if reportData
is of type IReportItemRegions
. 我们不知道
reportData
是否为IReportItemRegions
类型。 Before trying to access the property, you must ensure your object implements the property : 在尝试访问该属性之前,必须确保您的对象实现了该属性:
if ('regions' in reportData) {
console.log(reportData.regions)
}
If you want TypeScript to infer the type, you must get rid of find
et rewrite your code. 如果希望TypeScript推断类型,则必须摆脱
find
重写代码。 I've come with a simple implementation : 我提供了一个简单的实现:
let reportData: IReportItemRegions;
let i = 0;
while (!reportData && report.length < i) {
const currentReportData = report[i];
if (currentReportData.type === 'REGIONS') {
// Typescrit knows currentReportData is of type IReportItemRegions
reportData = currentReportData;
}
i++;
}
if (!reportData) {
return [];
}
console.log(reportData.regions);
Here is one possible solution:这是一种可能的解决方案:
interface IReportItemFactionStatus {
type: "FACTION_STATUS";
}
interface IReportItemRegions {
type: "REGIONS";
regions: readonly string[];
}
type IReportItem = IReportItemRegions | IReportItemFactionStatus;
const report = [
{
type: "REGIONS",
regions: ["region"]
},
{
type: "FACTION_STATUS"
}
] as const satisfies readonly IReportItem[]
type LookUp<T, TType> = Extract<T, { type: TType }>;
function lookup<TArr extends readonly any[], const TType extends TArr[number]['type']>(arr: TArr, type: TType) {
return arr.filter((d): d is LookUp<TArr[number], TType> => {
return d.type === type;
});
}
const x = lookup(report, "REGIONS")
// {
// readonly type: "REGIONS";
// readonly regions: readonly ["region"];
// }[]
const y = lookup(report, "FACTION_STATUS")
// {
// readonly type: "FACTION_STATUS";
// }[]
TS throws error as the return value will be of type IReportItemRegions | IReportItemFactionStatus
TS引发错误,因为返回值的类型为
IReportItemRegions | IReportItemFactionStatus
IReportItemRegions | IReportItemFactionStatus
. IReportItemRegions | IReportItemFactionStatus
。
If its of type IReportItemFactionStatus
, as there is no regions
in it. 如果其类型为
IReportItemFactionStatus
,则因为其中没有regions
。 So its should throw an error. 所以它应该抛出一个错误。
When you add this check: reportData.type !== "REGIONS"
, you are telling typescript that for cases when you get IReportItemFactionStatus
, you are returning before and console.log(reportData.regions);
当您添加以下检查:
reportData.type !== "REGIONS"
,您在告诉打字稿说,在得到IReportItemFactionStatus
情况下,您将返回before和console.log(reportData.regions);
becomes unreachable code. 成为无法访问的代码。 Hence no error.
因此没有错误。
Alternate way: 替代方式:
enum ReportType {
REGIONS = "REGIONS",
FACTION_STATUS = "FACTION_STATUS"
}
export interface IReportItem {
type: ReportType;
regions?: [];
}
// No need for this now
//export type IReportItem = IReportItemRegions | IReportItemFactionStatus;
export type IReport = Array < IReportItem > ;
// ... code ...
// report has type IReport
const reportData: IReportItem | null = report.find((d) => {
return d.type === ReportType.REGION;
});
if (!reportData) {
return [];
}
console.log(reportData.regions); // Typescript error here
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.