示例:
interface Tree {
[key: string]: Tree | {name: string}
}
const t: Tree = {
b: { name: 'test 1' },
c: {
d: { name: 'test 2' }
},
e: {
f: {
g: { name: 'test 3' }
}
}
}
const { b, c, e } = t
const testName1 = b.name // name
const testName2 = c.d.name // Error Property 'd' does not exist on type 'Tree | { name: string; }'. Property 'd' does not exist on type '{ name: string; }'.(2339
const testName3 = e.f.g.name // Error Property 'f' does not exist on type 'Tree | { name: string; }'. Property 'f' does not exist on type '{ name: string; }'.(2339)
无法访问财产c.d
和e.f
。
类型Tree
有什么问题?
可以使用这种方法:
const { d } = c as Tree
const testName2 = d.name
但是也许有更方便的方法吗?
答案 0 :(得分:1)
编译器是正确的:这是一种容易出错的处理方式。您将其用t
注释为Tree
的事实意味着您告诉编译器忘记它知道的任何特定类型信息,并假定它是一棵通用树。
这会引起问题:在通用树(如您所定义的树)中,任何时候都可能有子树:因此c.d可能只是树本身。如果您没有将其用于树遍历或类似的事情,并且需要确保存在特定的树结构,那么您需要其他的东西。另外,按照定义方式,您将为所有可能的字符串键定义一个子树,没有任何未定义的东西。
如果您想将其用于常规树类型输入,我将像这样更改您的定义并添加一个类型保护。 Playground link
interface TreeLeaf {
name: string;
}
interface Tree {
[key: string]: Tree | TreeLeaf | undefined
}
const t: Tree = {
b: { name: 'test 1' },
c: {
d: { name: 'test 2' }
},
e: {
f: {
g: { name: 'test 3' }
}
}
};
function isLeaf(val: Tree | TreeLeaf | undefined): val is TreeLeaf {
return !!val && typeof val.name === "string";
}
const { b, c, e } = t
if (isLeaf(b)) {
console.log(b.name);
}
if (c && !isLeaf(c) && isLeaf(c.d)) {
const testName2 = c.d.name // No longer an error
}