typescript - Apollo 的 TypeScript 类型使用Mutation 的 refetchQueries?
问题描述
我有一个带有 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
}
}
]
})
解决方案
简短的回答
你真的不能。从 Apollo Client v3.4.0 开始refetchQueries
,它的类型最终会解析为:
| "all"
| "active"
| Array<string | DocumentNode | QueryOptions>`
Typings 没有类型参数(通用)以允许您指定自己的类型为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
本身是在这里输入的。
在这些类型中,没有类型参数(通用)允许您为refetchQueries
. 尽管即使泛型可用,您也需要解决尝试创建强制执行“给定具有类型属性的对象query
的类型的问题,我们需要variables
具有另一种类型的另一个属性”“。为什么这很重要?嗯,要回答你需要问输入这个有什么意义?你要确保如果你使用给定的查询,任何传入的错误类型的变量都会在编译时被捕获运行时和用户遇到错误的风险降低。使用函数很容易,因为函数的标识符和类型的标识符是相同的(它内置于类型所说的函数“给定这个函数它应该有“)类型的参数,但在我们的例子中,我们没有函数。因此,这就是为什么我用“你不能真的”打开我的答案。
我确实探索了利用typeof
如下的可能性:
interface MyQueryNameRefetch extends QueryOptions {
query: typeof MY_QUERY;
variables: QueryVariables
}
在我最初的测试中,我只使用了 const 字符串,并错误地将效果推断为上述可能性。进一步的测试表明,这并没有达到我们想要的效果,因为只有文字类型和枚举成员在使用 a 声明或断言时不会扩大它们的类型const
。
您可以获得的最接近的是键入变量:
refetchQueries: [
{
query: MY_OTHER_QUERY,
variables: {
foo: 'bar'
}
} as QueryOptions<{ foo: string }>
]
关于 Arvid 答案的注释
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
},
}),
],
});
}
这与铸造非常相似,但实际上并不是一个好主意。它有铸造的缺点(你必须记住使用它);以及其他一些,例如具有运行时效果,因为该函数将存在于编译代码以及调用堆栈中(您的类型不应该具有运行时效果)以及对代码理解方式的影响(函数传达一些单位运行时功能,但这里没有运行时功能)。
再次,根本原因归结为我之前描述的关于标识符和类型如何断开连接的问题。
推荐阅读
- java - 如何在 JavaFX 的文本字段中禁用空格键?
- go - 在第一个空白字符之后,Go 构建未选择 CXX 环境变量
- java - 这个 lambda 表达式中的 imageProxy 参数是如何定义的?
- flutter - 如何使用 Radius CustomPainter 像这个样机一样创建弧
- javascript - Onclick 按钮只能工作一次。div 滑块 scrollIntoView
- mysql - 用于更改工作台中存在的所有模式的 SQL 查询?
- javascript - 分页在php网页中的page2上不起作用
- haskell - 字符串加倍?
- python - 用于命名字符串常量的 Python 构造
- python - 通过python合并两个外部边缘