我正在将我的本机项目从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
。
打字稿中是否可以接受通用的参数化键和值,但还可以包含其他字段?
答案 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" }
}