我试图让Apollo与TypeScript集成。 我有一个React类,如下所示:
interface Data {
allVendors: Array<VendorType>;
}
class AllVendorsQuery extends Query<Data> {}
const ShowVendors: React.SFC<> = props => {
return (
<AllVendorsQuery query={fetchVendors}>
{({ loading, error, data: { allVendors } }) => {
if (loading) {
return 'Loading...';
}
if (error) {
return `Error! ${error.message}`;
}
return (
allVendors &&
allVendors.map((vendor, index: number) => {
return (
<div key={`${vendor.name}_${index}`}>
#<strong>{vendor.id}</strong>
{vendor.name}
</div>
);
})
);
}}
</AllVendorsQuery>
);
};
export default ShowVendors;
查询是:
export default gql`
query GetVendors {
allVendors {
id
name
}
}
`;
TypeScript抱怨[ts] Type 'Data | undefined' has no property 'allVendors' and no string index signature.
出现在这一行:{({ loading, error, data: { allVendors } })
。
但是,如果我使用apollo-connect
而不是Query组件重构代码,我不会从TypeScript中得到任何抱怨:
import { graphql, compose, QueryResult } from 'react-apollo';
interface ShowVendorsProps {
data: QueryResult & { allVendors?: VendorType[] };
}
class ShowVendors extends React.Component<ShowVendorsProps> {
render() {
const {
data: { allVendors }
} = this.props;
if (allVendors && allVendors.length > 0) {
return (
<div>
{allVendors.map((vendor, index: number) => {
return (
<div key={`${vendor.name}_${index}`}>
#<strong>{vendor.id}</strong>
{vendor.name}
</div>
);
})}
</div>
);
} else {
return 'Loading';
}
}
}
export default compose(graphql(fetchVendors))(ShowVendors);
两者有什么区别?如何重写第一个语句的类型?
答案 0 :(得分:3)
有一个小的库和一个CLI,可以为服务器(根据您的架构)和客户端(根据您的架构和GraphQL文档)生成TypeScript类型。它还会生成解析器签名并且非常可定制。
您可以在这里尝试:https://github.com/dotansimha/graphql-code-generator
这里有关于该软件包的博客文章; https://medium.com/the-guild/graphql-code-generator-for-typescript-react-apollo-7b225672588f
其背后的想法是允许开发人员充分利用GraphQL和生成的类型,并使自定义生成的输出更容易。
它还可以根据您的需要生成反应阿波罗组件。
答案 1 :(得分:1)
由于您在第一个代码块中使用data
解构data: { allVendors }
,因此TypeScript会抱怨因为data
可能未定义,例如数据仍在加载时。
因此,对于TS没有抱怨,您可以在加载检查后进行解构,使用allVendors
的默认值,例如:
interface Data {
allVendors: Array<VendorType>;
}
class AllVendorsQuery extends Query<Data> {}
const ShowVendors: React.SFC<> = props => {
return (
<AllVendorsQuery query={fetchVendors}>
{({ loading, error, data }) => {
if (loading) {
return 'Loading...';
}
if (error) {
return `Error! ${error.message}`;
}
// If data is not undefined, then it sets allVendors accordingly.
// Otherwise it sets it to null (which you check for anyways below)
const {allVendors} = data || {allVendors: null};
return (
allVendors &&
allVendors.map((vendor, index: number) => {
return (
<div key={`${vendor.name}_${index}`}>
#<strong>{vendor.id}</strong>
{vendor.name}
</div>
);
})
);
}}
</AllVendorsQuery>
);
};
export default ShowVendors;