Typescript-如何使用嵌套映射类型

时间:2019-10-03 10:14:33

标签: typescript

给了我一个无法修改的大型复杂接口X,我想基于接口X内的属性和子属性来定义一些较小的类型,这些类型和子属性我想用作函数参数的类型。我还想避免单独重新声明X中已经存在的内容。

interface X {
  a:number;
  c:{
    aa:number;
    cc:{
      aaa:string;
    }
  },
  d?:{
    aa:number;
    cc:{
      aaa:string;
    }
  },
  e:{
    aa:number;
    cc:{
      aaa:string;
    }
  }[]
}

我知道我可以使用映射类型访问子类型[编辑说明:子类型是错误的术语,应称为嵌套级类型,请参见下面的答案],这应该是对象的内容,例如:

type C = X["c"]; // { aa:number; cc:{ aaa:string } } 

type C_CC = X["c"]["cc"]; // { aaa: string }

type D = X["d"]; // { aa:number; cc:{ aaa:string } } | undefined

但是,当该属性可能未定义时,事情变得有些繁琐。如果我想获得X.d.cc ...(应该给出{aaa:string})的类型,我该怎么做?还是有可能?

以下两次尝试都会产生错误:

type D_CC1 = X["d"]["cc"];  // error? Due to the (d?) possibly undefined?
type D_CC2 = Required<X["d"]>["cc"];  // error also?

另外,当涉及数组时,例如在上面的E中,我也有些困惑:

type E = X["e"]; // { aa:number; cc:{ aaa:string } }[]
type E_CC1 = X["e"]["cc"]; // error
type E_CC2 = X["e"][0]["cc"]; // got the result I wanted: { aaa: string }

第三行似乎有效,但是我不确定使用[0]的逻辑是什么-似乎很hack。我想知道这是否正确。

编辑:将类型名称从D_CC更改为D_CC1和D_CC2,以避免产生歧义。

2 个答案:

答案 0 :(得分:2)

如果查看一下界面,您会发现/std:c++latest /O2 /W3 属性实际上定义为数组。

e

这就是您需要使用索引器e:{ aa:number; cc:{ aaa:string; } }[] // NOTICE THIS! 来获取该数组的项目类型的原因。这不是hack,实际上是从2.1开始添加在打字稿中的,官方名称为indexed access types, also called lookup types

答案 1 :(得分:1)

只是一个细节,但是为了不混淆术语,界面中的内容不是子类型,而是嵌套级别的类型。嵌套类型具有顶级类型。子类型是可以在需要具有该子类型的类型的任何地方使用的类型。

接下来,您所说的映射类型实际上就是我们所说的键入运算符。这是一种在形状中查找属性类型的方法。

映射类型用于映射对象的键和值类型,看起来像这样:

type MyMappedType = {
  [Key in K]: ValueType
}

这也是您可以利用keyof运算符的地方。 Key in keyof Something

例如,要使形状中的所有字段为可选(为此,有一个名为Partial<Object>的内置映射类型),可以使用mapped types

type ShapeAllOptional = {
  [K in keyof MyShape]?: MyShape[K]
}

现在继续您的问题。

type D_CC1 = X["d"]["cc"];  // error? Due to the (d?) possibly undefined?

您可以使用类似的东西

type myStype = NonNullable<X['d']>['cc']

关于使用

type E_CC1 = X["e"]["cc"]; // error
type E_CC2 = X["e"][0]["cc"]; // got the result I wanted: { aaa: string }

是的,它是一个数组,每个项目都具有该形状。我不知道这是不是很老套,但是我确实看到了一些看起来“干净”的东西。

type E_CC2 = X["e"][number]["cc"];

我知道没有更好的方法。

啊,我差点忘了。

type D_CC2 = Required<X["d"]>["cc"];  // error also?

请注意,此处要说的是使X ['d']中的所有属性成为必需,即aacc,它们已经是必需的。 Required<X>我想实现您想要的目标。