指定具有未知参数的函数数组会引发类型错误
Specifying array of functions with unknown arguments throws a typeerror
我设置了一个相当简单的钩子,叫做 useField.ts
,它的定义如下:
type CheckFunction = <T>(input: T, ...args: unknown[]) => unknown
export const useField = <T>(
input: T,
...checkFunctions: CheckFunction[]
) => {
// .... and the code goes here, but irrelevant for the question
}
之后,我开始在 useField.test.tsx
中按以下方式编写测试:
import { renderHook } from '@testing-library/react-hooks'
import { useField } from '../useField'
describe('useField error functions', () => {
const emailRegex = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/gi
const isValidEmail = (input: string): boolean => !!input.match(emailRegex)
test('Basic checkFunction', () => {
const { result } = renderHook(() => useField('valid@email.com', isValidEmail)
// ^ I get a type-error here
})
})
我尝试传递 isValidEmail
函数的行有以下 typescript 错误:
Argument of type '(input: string) => boolean' is not assignable to parameter of type 'CheckFunction'.
Types of parameters 'input' and 'value' are incompatible.
Type 'T' is not assignable to type 'string'.
现在这可以通过将 checkFunctions
的定义分配给 any
从技术上解决,但这是我想提防的事情,因为它有点违背了类型检查的目的。
我也想过用泛型,但问题是,参数可以有多种类型,不能用一个泛型的数组来表达
知道我做错了什么吗?因为从逻辑的角度来看,unknown
的用法在这里似乎是正确的。
假设你的检查函数只接受一个参数,为什么你将它定义为接受多个值?例如。 ...args: unknown[]
。您还可以指定它 returns 一个 boolean
而不是 unknown
.
你可以做这样的事情,它实际上使用了一个泛型,但据我所知似乎很适合你的用例:
export const useField = <T>(
input: T,
...checkFunctions: Array<(value: T) => boolean>
) => {
// .... and the code goes here, but irrelevant for the question
}
const result = useField('someString', validator1, validator2);
// ^ It would know T is a string here, since the input is a string
// Therefore it'll check that `validator1` is of the type `(value: string) => boolean`
const result = useField('someString', str => {
// TypeScript knows the type of `str` is string
return str.includes('something');
});
// This would error:
const result = useField<string>(123, validator1);
// As well as this due to the validator accepting the wrong value:
const result = useField('string', (value: number) => true);
这是假设 useField
需要实际输入的值,而不是 <input>
元素的 id/name。否则没有理由让 input
成为通用的(毕竟 name/id 总是一个字符串)并且你不会命名 <input>
valid@email.com
但 email
相反。
问题中的更新代码。
您对“通用”CheckFunction
类型的定义不正确。改用这个:
type CheckFunction<T> = (input: T, ...args: unknown[]) => unknown
export const useField = <T>(
input: T,
...checkFunctions: CheckFunction<T>[]
) => {
// .... and the code goes here, but irrelevant for the question
}
您使用 type Type = <T>(...
的版本基本上告诉 TypeScript“此函数具有 a 泛型,但在 Type
之外无关紧要”。如果您使用 type Type<T>
,则您告诉 TypeScript 该类型很重要,例如应该由类型的用户指定。
简而言之,通过使用 type Type<T>
,您可以让 useField
指定 Type
中的 T
代表什么,例如与 useField
的 T
.
类型相同
我设置了一个相当简单的钩子,叫做 useField.ts
,它的定义如下:
type CheckFunction = <T>(input: T, ...args: unknown[]) => unknown
export const useField = <T>(
input: T,
...checkFunctions: CheckFunction[]
) => {
// .... and the code goes here, but irrelevant for the question
}
之后,我开始在 useField.test.tsx
中按以下方式编写测试:
import { renderHook } from '@testing-library/react-hooks'
import { useField } from '../useField'
describe('useField error functions', () => {
const emailRegex = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/gi
const isValidEmail = (input: string): boolean => !!input.match(emailRegex)
test('Basic checkFunction', () => {
const { result } = renderHook(() => useField('valid@email.com', isValidEmail)
// ^ I get a type-error here
})
})
我尝试传递 isValidEmail
函数的行有以下 typescript 错误:
Argument of type '(input: string) => boolean' is not assignable to parameter of type 'CheckFunction'.
Types of parameters 'input' and 'value' are incompatible.
Type 'T' is not assignable to type 'string'.
现在这可以通过将 checkFunctions
的定义分配给 any
从技术上解决,但这是我想提防的事情,因为它有点违背了类型检查的目的。
我也想过用泛型,但问题是,参数可以有多种类型,不能用一个泛型的数组来表达
知道我做错了什么吗?因为从逻辑的角度来看,unknown
的用法在这里似乎是正确的。
假设你的检查函数只接受一个参数,为什么你将它定义为接受多个值?例如。 ...args: unknown[]
。您还可以指定它 returns 一个 boolean
而不是 unknown
.
你可以做这样的事情,它实际上使用了一个泛型,但据我所知似乎很适合你的用例:
export const useField = <T>(
input: T,
...checkFunctions: Array<(value: T) => boolean>
) => {
// .... and the code goes here, but irrelevant for the question
}
const result = useField('someString', validator1, validator2);
// ^ It would know T is a string here, since the input is a string
// Therefore it'll check that `validator1` is of the type `(value: string) => boolean`
const result = useField('someString', str => {
// TypeScript knows the type of `str` is string
return str.includes('something');
});
// This would error:
const result = useField<string>(123, validator1);
// As well as this due to the validator accepting the wrong value:
const result = useField('string', (value: number) => true);
这是假设 useField
需要实际输入的值,而不是 <input>
元素的 id/name。否则没有理由让 input
成为通用的(毕竟 name/id 总是一个字符串)并且你不会命名 <input>
valid@email.com
但 email
相反。
问题中的更新代码。
您对“通用”CheckFunction
类型的定义不正确。改用这个:
type CheckFunction<T> = (input: T, ...args: unknown[]) => unknown
export const useField = <T>(
input: T,
...checkFunctions: CheckFunction<T>[]
) => {
// .... and the code goes here, but irrelevant for the question
}
您使用 type Type = <T>(...
的版本基本上告诉 TypeScript“此函数具有 a 泛型,但在 Type
之外无关紧要”。如果您使用 type Type<T>
,则您告诉 TypeScript 该类型很重要,例如应该由类型的用户指定。
简而言之,通过使用 type Type<T>
,您可以让 useField
指定 Type
中的 T
代表什么,例如与 useField
的 T
.