我有一个 API,它返回大量数据,这些数据是对象的混合体,其中数据结构根据类型而变化,我不明白我应该如何为其创建一个好的类型结构。 我相信我做得对,但是当我尝试检查它是哪种类型时,我收到错误属性 X 在类型上不存在。
type EchoGroup = {
group: {
img: { name: string; type: "ECHO" };
specialData: { meta: string; copy: string }[];
};
owner: boolean;
};
type CharlieGroup = {
group: {
img: { name: string; type: "CHARLIE" };
specialData: { meta: string; usage: string; price: number }[];
};
owner: boolean;
};
const sample: (EchoGroup | CharlieGroup)[] = [
{
group: {
img: { name: "Test 1", type: "CHARLIE" },
specialData: [
{ meta: "string", usage: "private", price: 10 },
{ meta: "string", usage: "public", price: 20 },
],
},
owner: false,
},
{
group: {
img: { name: "Test 2", type: "ECHO" },
specialData: [{ meta: "string", copy: "private" }],
},
owner: true,
},
];
sample.map((single: EchoGroup | CharlieGroup) => {
switch (single.group.img.type) {
case "ECHO":
console.log(single.group.specialData[0].copy);
// Error:
// Property 'copy' does not exist on type '{ meta: string; copy: string; }[] | { meta: string; usage: string; price: number; }[]'.
// Property 'copy' does not exist on type '{ meta: string; copy: string; }[]'.
break;
case "CHARLIE":
console.log(single.group.specialData[0].price);
break;
}
});
答案 0 :(得分:1)
问题是 typescript 的类型缩小了父对象的 doesn't narrow type 取决于子对象的判别值:
type A = { type: "a", a: number }
type B = { type: "b", b: number }
type X = { type: A, a: string }
type Y = { type: B, b: string }
declare let x: X | Y
if (x.type.type === "a") {
x.a // Type Error
x.type.a // no error. `x.type` is narrowed to A
}
<块引用>
判别属性仅适用于它直接所属的对象。因此,在您的示例中,在 if 块内,您可以访问 x.type.a(但不能访问 x.type.b),但对包含对象 x 没有影响。
有一个 PR 来提供这种功能。但它仍在进行中。
截至目前,在任何结构中缩小类型的唯一方法是将判别属性保持在同一级别或更高级别:
type EchoGroup = {
group: {
type: 'ECHO',
img: { name: string };
specialData: { meta: string; copy: string }[];
};
owner: boolean;
};
type CharlieGroup = {
group: {
type: 'CHARLIE',
img: { name: string };
specialData: { meta: string; usage: string; price: number }[];
};
owner: boolean;
};
...
sample.map((single: EchoGroup | CharlieGroup) => {
switch (single.group.type) {
case "ECHO":
console.log(single.group.specialData[0].copy); // works as expected
break;
case "CHARLIE":
console.log(single.group.specialData[0].price); // works too
break;
}
});