如何为条件类型赋值?

Dmi*_*sky 8 typescript

我正在尝试编写一个函数,使得第一个参数是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 编译器给了我一个错误,即它无法将条件类型解析为stringstring[]。这样做的正确方法是什么?

游乐场链接

Ale*_*hin 1

使用像这样的泛型类型参数真是令人头疼,我不确定它到底是如何工作的,但你几乎永远无法让打字稿缩小类型范围。如果将鼠标悬停在构造t内部if,您将看到它具有 type (f: P<B>) => void,而不是(f: string) => void(f: string[]) => void:它无法根据另一个变量来缩小一个变量的类型。我认为这是一个限制,目前我想不出任何方法来解决这个问题。我可能是错的,但我以前在更复杂的上下文中遇到过这种情况,并且必须更改函数的设计才能使其工作。

我认为在这种情况下你可以这样做t([file] as any)t(file as any)最后,这些类型的要点是强制以正确的方式调用函数。如果它被正确调用,那么它内部就知道要做什么,我认为值得在这里添加几个anys 。

您也可以使用重载来摆脱泛型,但这并不能解决问题:

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)

实际上不需要anys 的一种解决方案是使用对象,但这并不理想,因为您可能需要更改应用程序中的其他逻辑:

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)