如何在Typescript中为类型的参数设置键

时间:2018-12-05 20:47:21

标签: typescript flowtype

我正在将我的本机项目从Flow迁移到TypeScript,而我坚持的一部分是从Flow重新创建这种类型:

declare type ApolloData<T, nodeName: string = 'node'> = {
  [nodeName]: ?T,
  viewer?: ?Viewer,
  placeSearch?: ?PlaceConnection,
  contactIqLookup?: ?ContactIq,
};

这使我可以如下输入来自GraphQL的数据:

const data: ApolloData<Space> = fetchData();
const space: Space = data.node;
// OR
const data: ApolloData<Space, 'space'> = fetchData();
const space: Space = data.space;

我试图在TypeScript中重新创建它,这是我的第一次尝试:

type ApolloData<T, nodeName extends string = 'node'> = {
  [node: nodeName]: T | null;
  viewer?: Viewer | null;
  placeSearch?: PlaceConnection | null;
  contactIqLookup?: ContactIq | null;
}

但是,这会导致错误:TS1023: An index signature parameter type must be 'string' or 'number'.

经过研究,我了解了Record类型,这似乎很合适,所以我的第二次尝试更加成功:

type ApolloData<T, nodeName extends string = 'node'> = 
    Record<nodeName, T | null> &
    {
      viewer?: Viewer | null;
      placeSearch?: PlaceConnection | null;
      contactIqLookup?: ContactIq | null;
    }

但是与此有关的问题是,由于viewer: Viewer | null | T类型适用于该对象的所有属性,因此其他属性的类型为Viewer | null,而不仅仅是Record

打字稿中是否可以接受通用的参数化键和值,但还可以包含其他字段?

1 个答案:

答案 0 :(得分:1)

这个怎么样?只需将Record定义与其他静态属性进行分解,然后将它们组合起来

type ContactIq = { _type: "ContactIq" };
type PlaceConnection = { _type: "PlaceConnection" };
type Viewer = { _type: "Viewer" };

type DataOnly<T, nodeName extends string> = Record<nodeName, T | null>;

interface OtherAttributes {
  viewer?: Viewer | null;
  placeSearch?: PlaceConnection | null;
  contactIqLookup?: ContactIq | null;
}

type ApolloData<T, nodeName extends string = 'node'> = OtherAttributes & DataOnly<T, nodeName>;

const data1: ApolloData<string> = {
  node: "test",
  viewer: { _type: "Viewer" },
  contactIqLookup: { _type: "ContactIq" },
  placeSearch: { _type: "PlaceConnection" }
}

const data2: ApolloData<string, "abc"> = {
  abc: "test",
  viewer: { _type: "Viewer" },
  contactIqLookup: { _type: "ContactIq" },
  placeSearch: { _type: "PlaceConnection" }
}