带类型保护的Typescript条件类型

i2byvkas  于 2023-03-19  发布在  TypeScript
关注(0)|答案(2)|浏览(161)

我有这段代码,我在条件类型问题上遇到了麻烦,我试图推断一个作为函数参数接收的对象是否来自一个特定的类型,如果是,我希望它的参数类型会受到它的影响。
例如我的代码:

type Relation = "and" | "or";

type CertainType = { key: unknown };

export type InputType = CertainType["key"] | Array<CertainType["key"]>;

interface InputOptions<T extends InputType> {
  inputKey: T;
  relation: T extends Array<CertainType["key"]> ? Relation : never;
}

function isOptionsAreArrayOptions(
  options: InputType
): options is InputOptions<Array<CertainType["key"]>> {
  if (Array.isArray(options) && options.length > 1) {
    return true;
  }
  return false;
}

function someFunc<T extends InputType>(options: InputOptions<T>): boolean {
  if (isOptionsAreArrayOptions(options)) {
    // Options is now InputOptions<Array<CertainType["key"]>> (array).

    /* ---THIS IS WHAT I WANT TO CHECK---. */
    options.relation = 'and';

    if (options.relation === "and") {
      // Some code...
      return true;
      // in the else it has to be the "or".
    } else {
      // Some code...
      return true;
    }
  } else {
    // relation has to be never becasuse options is InputOptions<CertainType["key"]>;
    // Do something...
    return false;
  }
}

someFunc函数中使用typeguard之后,选项.relation将可赋值为值“or”|“and”,而在else部分中,它将是never
目前这是我得到的错误消息:Type '"and"' is not assignable to type '(T extends Array<CertainType["key"]> ? Relation : never) & Relation'.
代码沙箱链接:https://codesandbox.io/s/typescript-forked-n7k6wo

gudnpqoy

gudnpqoy1#

您可以尝试以下选项:作为选项类型的关系。

function someFunc<T extends InputType>(options: Relation): boolean {
...
}
mzillmmw

mzillmmw2#

好吧,问题是这个类型:

interface InputOptions<T extends InputType> {
  inputKey: T;
  relation: T extends Array<CertainType["key"]> ? Relation : never;
}

它允许不同的类型将InputType扩展为可选答案,并且不将结果限制为联合类型(InputType)所具有的结果。
我把它改成了这个类型:

type InputOptions<T> =
    T extends Array<CertainType["key"]> ?
    {inputKey: T, relation: Relation } :
    T extends CertainType["key"] ? {inputKey: T} : never;

通过将此类型转换为显式选项的联合类型,也可以获得类似的可行答案:

type A = {inputKey: Array<CertainType["key"]>, relation: Relation};
type B = {inputKey: CertainType["key"]};
type InputOptions = A | B;

在我看来,我宁愿隐式解决方案(第一个),因为显式子类型没有任何重要的意义。

相关问题