我有一个带有 TypeScript 类型的 Apollo useMutation 钩子:
const MY_MUTATION = gql`
mutation($source: String!) {
doSomething(source: $source) {
result
}
}
`
const [myMutation] = useMutation<ReturnPayloadType, MutationVariables>(MY_MUTATION);
当我使用它时,它给了我类型安全:
myMutation({
variables: {
source: 'some source',
// foo: 'bar' This would error if uncommented.
}
})
这是有效的,但现在我需要使用 refetchQueries
键。如何向其添加类型?
myMutation({
variables: {
source: 'some source',
// foo: 'bar' This would error if uncommented.
},
refetchQueries: [
{
query: MY_OTHER_QUERY,
variables: {
foo: 'bar' // I want to add type safety here
}
}
]
})
答案 0 :(得分:2)
你真的不能。从 Apollo Client v3.4.0 开始,输入 refetchQueries
以便最终解析为:
| "all"
| "active"
| Array<string | DocumentNode | QueryOptions>`
类型没有类型参数(通用)来允许您为 refetchQueries
指定自己的类型。我会在运行时依赖 GraphQL 的类型保护,并可能在编译时将类型转换作为次要保护。您可以将传递给 refetchQueries
的每个对象的类型转换为 QueryOptions
,并通过 QueryOption
的类型参数指定变量的类型。类型转换确实有一个警告,您需要记住使用它,并且它不能保证变量和查询的类型匹配。
myMutation({
variables: {
source: 'some source',
// foo: 'bar' This would error if uncommented.
},
refetchQueries: [
{
query: MY_OTHER_QUERY,
variables: {
foo: 'bar'
}
} as QueryOptions<{ foo: string }>
]
})
从 Apollo Client v3.4.0 开始,refetchQueries
选项的类型如下:
refetchQueries?:
| ((result: FetchResult<TData>) => InternalRefetchQueriesInclude)
| InternalRefetchQueriesInclude;
其中 InternalRefetchQueriesInclude
的类型为:
export type InternalRefetchQueriesInclude =
| InternalRefetchQueryDescriptor[]
| RefetchQueriesIncludeShorthand;
– https://github.com/apollographql/apollo-client/blob/release-3.4/src/core/types.ts#L35-L37
然后上面基本上解析为:
| "all"
| "active"
| Array<string | DocumentNode | QueryOptions>`
– https://github.com/apollographql/apollo-client/blob/release-3.4/src/core/types.ts#L26-L29
QueryOptions
本身的类型为 here。
在这些类型中,没有类型参数(通用)允许您为 refetchQueries
指定自己的类型。尽管即使泛型可用,您也需要解决尝试创建一个类型的问题,该类型强制“给定一个具有 type 属性 query
的对象,我们需要另一个属性 {{1 }} 与另一种类型”。为什么这很重要?好吧,要回答这个问题,您需要问输入这个的意义何在?您希望确保如果您使用给定的查询,任何传入的错误类型的变量都会在编译时而不是运行时被捕获,并降低用户遇到错误的风险。使用函数很容易,因为函数的标识符和类型的标识符是相同的(它内置于函数中,类型说“给定这个函数它应该有 type 的参数”)但是在我们的例子中,我们没有函数。因此,这就是我以“你真的不能”开头的原因。
我确实探索了利用 variables
的可能性,如下所示:
typeof
在我最初的测试中,我只使用了 const 字符串,并且错误地将效果推断为上述可能性。进一步的测试表明,这不会产生我们想要的效果,因为只有文字类型和枚举成员在使用 interface MyQueryNameRefetch extends QueryOptions {
query: typeof MY_QUERY;
variables: QueryVariables
}
声明或断言时不会扩展它们的类型。
最接近的是输入变量:
const
refetchQueries: [
{
query: MY_OTHER_QUERY,
variables: {
foo: 'bar'
}
} as QueryOptions<{ foo: string }>
]
你会像这样使用它:
function typedQuery<TVariables>(
options: QueryFunctionOptions<unknown, TVariables> & {
query: TypedDocumentNode<unknown, TVariables>;
},
) {
return options;
}
这与投射非常相似,但实际上并不是一个好主意。它具有强制转换的缺点(你必须记住使用它);以及其他一些,例如具有运行时效果,因为该函数将存在于编译代码和调用堆栈中(您的类型不应具有运行时效果)以及对代码理解方式的影响(函数传达某种单位运行时功能,但这里没有运行时功能)。
再次归结为我之前描述的有关标识符和类型如何断开连接的问题。
答案 1 :(得分:0)
我对 Apollo 不是很熟悉,但是您可以通过添加辅助函数来解决您的问题。在下面的代码中,我将其命名为 typedQuery
。很可能 Apollo 已经内置了这样一个函数,但同样,我对这个库还不够了解。
import { gql, QueryFunctionOptions, TypedDocumentNode, useMutation } from '@apollo/react-hooks';
const MY_MUTATION = gql`
mutation($source: String!) {
doSomething(source: $source) {
result
}
}
`;
type MyMutationPayloadType = { result: string };
type MyMutationVariables = {
source: string;
};
const MY_QUERY = gql`
query($value: Int!) {
findSomething(value: $value) {
someProperty
}
}
`;
type MyQueryVariables = {
value: number;
};
function typedQuery<TVariables>(
options: QueryFunctionOptions<unknown, TVariables> & {
query: TypedDocumentNode<unknown, TVariables>;
},
) {
return options;
}
function MyComponent() {
const [myMutation] = useMutation<MyMutationPayloadType, MyMutationVariables>(MY_MUTATION);
myMutation({
variables: {
source: 'a',
},
refetchQueries: [
typedQuery<MyQueryVariables>({
query: MY_QUERY,
variables: {
value: 1,
// value: 'a' <-- gives compiler error
},
}),
],
});
}