我正在尝试编写一个函数,使得第一个参数是boolean
,并且取决于这个参数是true
还是false
,第二个参数是一个接受 astring
或的函数string[]
。
这是我的尝试:
type P<B extends boolean> = B extends true ? string[] : string
function callback<B extends boolean>(b: B, t: (f: P<B>) => void) {
const file = 'file'
if (b) {
t([file]) // <-- Error: Argument of type 'string' is not assignable to parameter of type 'P<B>'.
} else {
t(file) // <-- Error: Argument of type 'string[]' is not assignable to parameter of type 'P<B>'.
}
}
callback(false, (f: string) => {}) // <-- No problem, resolves the correct argument type
callback(true, (f: string[]) => {}) // <-- No problem, resolves the correct argument type
Run Code Online (Sandbox Code Playgroud)
这适用于在调用函数时解析正确的参数类型。但是,在函数内部,TS 编译器给了我一个错误,即它无法将条件类型解析为string
或string[]
。这样做的正确方法是什么?
使用像这样的泛型类型参数真是令人头疼,我不确定它到底是如何工作的,但你几乎永远无法让打字稿缩小类型范围。如果将鼠标悬停在构造t
内部if
,您将看到它具有 type (f: P<B>) => void
,而不是(f: string) => void
或(f: string[]) => void
:它无法根据另一个变量来缩小一个变量的类型。我认为这是一个限制,目前我想不出任何方法来解决这个问题。我可能是错的,但我以前在更复杂的上下文中遇到过这种情况,并且必须更改函数的设计才能使其工作。
我认为在这种情况下你可以这样做t([file] as any)
,t(file as any)
最后,这些类型的要点是强制以正确的方式调用函数。如果它被正确调用,那么它内部就知道要做什么,我认为值得在这里添加几个any
s 。
您也可以使用重载来摆脱泛型,但这并不能解决问题:
function callback(b: true, t: (f: string[]) => void): void
function callback(b: false, t: (f: string) => void): void
function callback(b: boolean, t: ((f: string) => void)) | ((f: string[]) => void)) {
//
}
Run Code Online (Sandbox Code Playgroud)
实际上不需要any
s 的一种解决方案是使用对象,但这并不理想,因为您可能需要更改应用程序中的其他逻辑:
type Options = {
b: true
t: (f: string[]) => void
} | {
b: false
t: (f: string) => void
}
function callback(options: Options) {
const file = 'file'
if(options.b) options.t([file])
else options.t(file)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
272 次 |
最近记录: |