typescript - Cách làm cho Generics trở thành bắt buộc
Có cách nào để đánh dấu Generics là bắt buộc trong TypeScript không?
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' })
Sân chơi
Chỉnh sửa
Câu hỏi đã được trả lời và nó hoạt động rất tốt. Để hiểu rõ hơn tại sao tôi muốn sử dụng điều này, đây là một ví dụ.
onSubmit<UpdateUserMutation, UpdateUserMutationVariables>({
mutation: UpdateUserDocument,
variables: { id: user.id, user: formData },
refetchQueries: ['GetUserList'],
onSuccess: ({ data }) => history.push(`/users/${data.updateUser.id}`),
})
Khi tôi bỏ <UpdateUserMutation, UpdateUserMutationVariables>, tôi không biết data sẽ là gì trong hàm onSuccess của mình. Thêm vào đó, tôi cũng không biết phải truyền biến nào vào khóa variables. Chưa kể đến việc tích hợp với IDE :-).
Chắc chắn tôi có thể gõ trực tiếp { data }, nhưng tôi nghĩ bây giờ cách này thoải mái hơn nhiều, vì tôi không thể "quên" gõ và vì vậy tôi sẽ không bao giờ sử dụng sai/quên sử dụng các biến trong đối tượng variables và hàm onSuccess.
Đối với những ai tò mò, đây là cách hàm onSubmit của tôi trông như bây giờ:
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)
}
Câu trả lời #1
Cố tình làm suy yếu suy luận kiểu dường như không may, nhưng nếu tôi muốn, đây là cách tôi có thể thực hiện:
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)
}
Ý tưởng là sử dụng các giá trị mặc định của tham số kiểu tổng quát để cho chúng ta nhiều kiểm soát hơn về những gì xảy ra với các tham số kiểu không được suy luận, và để thêm một số tham số kiểu phụ nhằm loại bỏ các vị trí suy luận kiểu khỏi trình biên dịch. Các kiểu Result và Variables không thể được suy luận từ các giá trị được truyền vào của các thuộc tính foo và bar; chúng thậm chí không được đề cập ở bất cứ đâu trong chữ ký kiểu. Điều đó có nghĩa là nếu Result và Variables không được chỉ định thủ công, chúng sẽ mặc định thành kiểu tuple kỳ lạ dưới dạng [Error, "error message"]. Kiểu tuple kỳ lạ đó là một cách giải quyết tạm thời do thiếu một kiểu "invalid" trong TypeScript. Tôi có thể đã chọn never thay vào đó, nhưng khi đó thông báo lỗi có thể sẽ khó hiểu hơn.
Dù sao foo sẽ suy ra R, và bar sẽ suy ra V, mà phải có thể gán cho Result và Variables tương ứng. Điều này có nghĩa là nếu bạn không chỉ định Result và Variables, chúng sẽ mặc định là một số kiểu lỗi, và sau đó foo và bar sẽ bị giới hạn bởi kiểu lỗi đó, và bạn sẽ nhận được một lỗi:
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"'
Nếu bạn thực sự chỉ định Result và Variables thủ công, thì R và V sẽ bị giới hạn theo chúng (và sẽ mặc định theo chúng), nên sẽ hoạt động giống như phiên bản trước của bạn:
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
Nó xấu xí, bởi vì ngôn ngữ không muốn bạn làm điều này... suy luận kiểu thường là điều tốt. Nhưng đây là điều bạn yêu cầu, nên... hoan hô? Hy vọng điều đó giúp ích. Chúc may mắn!
