TypeScript编译器认为带有类型索引的递归联合类型是一个字符串?

时间:2017-08-16 21:03:56

标签: typescript

Link to TypeScript Playground

interface Model {
  [key: string]: string | number | boolean | Model | Model[];
}
interface ApiResponse {
  [key: string]: Model[];
}
async function main(): Promise<void> {
  const r = await api('foos_and_bars');
  console.log(r.bars[0].baz.name); //  Problem
  console.log(r.foos[0].fuzzies[1].name); // Implicit any
}
main();
async function api(endpoint: string): Promise<ApiResponse> {
  // Faked response:
  return {
    foos: [ { name: 'Foo 1', fuzzies: [{ name: 'Fuzzy 1' }, { name: 'Fuzzy 2'}] } ],
    bars: [ { name: 'Bar 1', baz: { name: 'Baz 1' } } ]
  }
}

在上面的TypeScript代码中,我打算使用Model接口,我打算像这样运行:

  • 任何模型都是具有任意数量属性的对象
  • 这些属性可以是字符串,数字,布尔值,其他模型或模型数组。

但是如果我使用这个接口并尝试读取它上面的一些属性,我会得到编译器错误,我不会期望。

对于第一个控制台日志,我得到:

Property 'name' does not exist on type 'string | number | boolean | Model | Model[]'.
Property 'name' does not exist on type 'string'.

对于第二个控制台日志(启用了noImplicitAny标志):

Element implicitly has an 'any' type because type 'string | number | boolean | Model | Model[]' has no index signature.

我的界面在这里做错了什么?

1 个答案:

答案 0 :(得分:3)

编译器是正确的。

第一条错误消息:

console.log(r.bars[0].baz.name);

表示:

  

财产&#39;名称&#39;类型&#39;字符串|中不存在号码|布尔值|型号|模型[]&#39 ;.
  财产名称&#39;类型&#39;字符串&#39;。

上不存在

情况确实如此。编译器不知道r.bars[0].baz属于Model类型,它知道可以属于该类型,但它也可以是string }(或number等) 联盟类型仅具有所有包含类型共享的属性 您可以通知编译器您知道类型是什么:

console.log((r.bars[0].baz as Model).name);

相同的错误几乎相同,r.foos[0].fuzzies的类型未知,它可能是联合中的一种类型,因此您需要以相同的方式让编译器知道:

console.log((r.foos[0].fuzzies as Model[])[1].name);