有没有办法在 typescript 中将泛型标记为强制性的?
function onSubmit<Result, Variables>({
foo,
bar
}: {
foo: Result
bar: Variables
}) {
console.log(foo, bar)
}
// this should not be possible without passing the Generics
onSubmit({ foo: 'foo', bar: 'bar' })
// this works as expected
onSubmit<number, number>({ foo: 'foo', bar: 'bar' })
编辑
问题已得到解答,效果非常好。为了更好地理解我为什么要使用它,这里有一个例子。
onSubmit<UpdateUserMutation, UpdateUserMutationVariables>({
mutation: UpdateUserDocument,
variables: { id: user.id, user: formData },
refetchQueries: ['GetUserList'],
onSuccess: ({ data }) => history.push(`/users/${data.updateUser.id}`),
})
当我省略 <UpdateUserMutation, UpdateUserMutationVariables>
时,我不知道什么data
会在我的onSuccess
功能。此外,我不知道必须将哪些变量传递给 variables
key 。更不用说 IDE 集成了:-)
我当然可以输入 { data }
直接,但我认为现在它更舒服,因为我不能“忘记”输入,所以我永远不会使用错误/忘记使用 variables
中的变量对象和 onSuccess
功能。
对于好奇的人,这就是我的 onSubmit
功能现在看起来:
function onSubmit<
Result = [Error, 'Please specify the Result type parameter'],
Variables = [Error, 'Please specify the Variables type parameter'],
R extends Result = Result,
V extends Variables = Variables
>({
mutation,
variables,
refetchQueries,
onSuccess,
}: {
mutation: DocumentNode
variables: V
refetchQueries: ((string | PureQueryOptions)[]) | (string | PureQueryOptions)[]
onSuccess: (response: FetchResult<R, Record<string, any>, Record<string, any>>) => void
}) {
client
.mutate<R>({
mutation,
variables,
refetchQueries,
})
.then(response => {
setErrors({})
onSuccess(response)
})
.catch(handleErrors)
}
最佳答案
故意阻碍类型推断似乎很不幸,但如果我愿意,我可能会这样做:
function onSubmit<
Result = [Error, "Please specify the Result type parameter"],
Variables = [Error, "Please specify the Variables type parameter"],
R extends Result = Result,
V extends Variables = Variables
>({
foo,
bar
}: {
foo: R
bar: V
}) {
console.log(foo, bar)
}
想法是使用generic type parameter defaults让我们更好地控制非推断类型参数会发生什么,并添加一些额外的类型参数以从编译器中删除类型推断站点。 Result
和 Variables
类型无法从 foo
和 bar
属性的传入值中推断出来;它们甚至没有在类型签名中的任何地方被提及。这意味着如果 Result
和 Variables
不是手动指定的,它们将默认为 [Error, "error message"] 形式的怪异元组类型
。那个奇怪的元组类型是缺少 "invalid" type 的解决方法。在 typescript 中。我本可以选择 never
,但这样错误消息可能会更含糊。
无论如何 foo
将推断出 R
,而 bar
将推断出 V
,这必须可分配给 Result
和 Variables
分别。这意味着如果您不指定 Result
和 Variables
,它们将默认为某种错误类型,然后是 foo
和 bar
将被限制为该错误类型,您将得到一个错误:
onSubmit({ foo: 'foo', bar: 'bar' }) // error
// ~~~ ~~~
// 'string' not assignable to 'Error, "Please specify the Result type parameter"'
// 'string' not assignable to 'Error, "Please specify the Variables type parameter"'
如果您确实手动指定了Result
和Variables
,那么R
和V
将受限于它们(并将默认为它们),因此应该与您以前的版本一样工作:
onSubmit<string>({ foo: 'foo', bar: 'bar' }) // error
// ~~~
// 'string' not assignable to 'Error, "Please specify the Variables type parameter"'
onSubmit<number, number>({ foo: 3, bar: 4 }) // okay
onSubmit<number, number>({ foo: 'foo', bar: 'bar' }) // error
// ~~~ ~~~
// 'string' not assignable to 'number' x2
这很丑陋,因为语言不希望您这样做...类型推断通常是一件好事。但这是你要求的,所以……是吗?希望有所帮助。祝你好运!
关于typescript - 如何强制泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55610260/