如何使泛型成为强制性

时间:2019-04-10 10:28:18

标签: 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' })

Playground

编辑

该问题已得到回答,它就像一个咒语。为了更好地理解我为什么要使用此功能,这是一个示例。

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键。更不用说IDE集成了:-)

可以肯定的是,我可以直接键入{ data },但是现在我觉得它更舒服了,因为我不能“忘记”键入,因此我永远不会在{{ 1}}对象和variables函数。

对于好奇的人,这是我的onSuccess函数现在的外观:

onSubmit

1 个答案:

答案 0 :(得分:5)

故意使类型混乱的推断似乎很不幸,但是如果我愿意的话,这就是我可能要做的事情:

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来使我们对非推断类型参数发生的事情有更多的控制,并添加一些额外的类型参数以从编译器中删除类型推断站点。类型ResultVariables不能从传递的foobar属性的值中推断出来。在类型签名中甚至都没有提到它们。这意味着,如果未手动指定ResultVariables,它们将默认为[Error, "error message"]形式的怪异元组类型。对于TypeScript中缺少"invalid" type的情况,该奇怪的元组类型是一种解决方法。我本来可以选择never,但是错误消息可能更含糊。

无论如何,foo会推断R,而bar会推断V,必须分别分配给ResultVariables。这意味着如果您不指定ResultVariables,它们将默认为某种错误类型,然后foobar将被限制为该错误。键入,您将得到一个错误:

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"'

如果您要做手动指定ResultVariables,则RV将被限制在它们上(并且默认为它们),因此应与以前的版本相同:

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

这很丑陋,因为该语言不希望您这样做...类型推断通常是一件好事。但这就是您要的,所以...是吗?希望能有所帮助。祝你好运!