Typescript 中的多种类型谓词

Ada*_*son 5 typescript typescript-generics typescript-typings

我有一个例子,我经常一起检查布尔值和另一个联合类型的值。虽然它们在逻辑上是相连的,并且假设可以只检查其中之一,但我需要检查两者,以便 TS 编译器知道这两种类型。

let multiple: boolean
let value: Array<string> | string 
...
if (multiple && isArray(value)) {
  // TS knows multiple === true and value is an Array
}
Run Code Online (Sandbox Code Playgroud)

有没有办法编写类型检查函数,其中类型谓词断言多个值?

像这样的东西:

// Not valid Typescript
function isMulti (
  multi: boolean, 
  value: Array<string> | string
): (multi is true) && (value is Array<string>) {
  return multi && isArray(value)
}
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,我只需检查即可isArray,但有些情况下我想重复使用上面的检查。这可能吗?


回复@kaya3:

为了给出更准确的用例,我有类似以下内容:

我可以将multiple和分配value给具有 DiscriminatedUnion 类型的对象,但这会增加比我认为需要的更多的复杂性。

type ValueType<M extends boolean> = M extends true ? Array<string> : string;

interface PropTypes<M extends boolean> {
  multiple: M,
  // more properties
}

type DiscriminatedUnion = {
  multiple: true,
  value: Array<string>
} | {
  multiple: false,
  value: string
}

function myFunction<M extends boolean>({
  multiple
}: PropTypes<M>) {

  let value: ValueType<M>;

  // ... later

  if (multiple) {
    // TS will not assert the type of `value` here
  }

  // Trying discriminated union
  // TS Error: Type '{ multiple: boolean; value: string | string[]; }' is not assignable to type '{ multiple: false; value: string; }'
  let obj: DiscriminatedUnion = {
    multiple,
    value
  }
}
Run Code Online (Sandbox Code Playgroud)

kay*_*ya3 6

目前无法通过这种方式解决您的问题;@jcalz 很有帮助地指出,有一个开放的功能请求。也就是说,您的问题可能可以通过不同的方式得到更好的解决。

对于几乎任何问题,比如“我有这两个值,我如何告诉 Typescript 它们的类型是相关的?”,答案是将它们作为属性放在一个对象中。然后,您可以将对象的类型设置为可区分联合,以便对其中一个属性进行测试可以缩小整个对象的类型范围。

type DiscriminatedUnion =
    | {multiple: false, value: string}
    | {multiple: true, value: string[]}

declare let obj: DiscriminatedUnion;

if(obj.multiple) {
    // here, obj.value is narrowed to string[]
    obj.value
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接