javascript - typescript:从条件类型派生类型

标签 javascript arrays typescript string types

typescript 支持 Conditional Types .
但是当我尝试设置 op 的值时作为字符串,它给了我错误,我如何检查类型和赋值?

export const t = <IsMulti extends boolean = false>(): void => {
    const value = 'test';
    type S = string;
    type D = IsMulti extends true ? S[] : S;
    const op: D = value;
    console.log(op);
};
错误:Type 'string' is not assignable to type 'D'.我什至尝试添加相同类型的参数 IsMulti并基于它添加检查
export const t = <IsMulti extends boolean = false>(isMulti: IsMulti): void => {
    const value = 'test';
    type S = string;
    type D = IsMulti extends true ? S[] : S;
    if (!isMulti) {
        const op: D = value;
        console.log(op);
    }
};
它仍然给出同样的错误。
enter image description here

最佳答案

评价conditional types这取决于尚未指定的 generic类型参数通常由编译器延迟;如果编译器不确切知道 IsMulti是,那么它不知道到底是什么IsMulti extends true ? S[] : S是,所以它不会让你分配一个类型的值(比如)S到那个条件类型,因为它无法验证这是一个类型安全的操作。编译器甚至没有真正尝试评估这种条件类型。它使它们成为不透明的东西,几乎没有任何东西可以分配给它。
对于您的第一个示例,这是编译器所需的行为;分配 string 确实不安全至op因为D很可能是string[] .没有什么能阻止某人调用 t<true>() .只是因为IsMulti有一个 defaultfalse不代表是false .

对于您的第二个示例,这是当前 TypeScript 的限制。编译器不能使用 control flow analysis缩小类型参数。因此它无法验证可分配性参见 microsoft/TypeScript#33912详情。
当您查看 if (!isMulti) ,编译器缩小 isMulti 的类型在 IsMulti 的后续代码块内只需输入 false :

export const t = <IsMulti extends boolean = false>(isMulti: IsMulti): void => {
  if (!isMulti) {
    // isMulti is now known to be false 
    const fls: false = isMulti; // okay
    const tru: true = isMulti; // error
  }
};
但它并没有缩小类型参数IsMulti本身。通常这也是编译器期望的行为,因为 IsMulti extends boolean表示 IsMulti实际上可能是完整的union boolean (而不是只是 true 或只是 false ),所以检查类型的值 IsMulti对缩小 IsMulti 没有用处本身。所有你能说的 if (!isMulti)IsMulti不能只是true ...但它可能仍然是 boolean .当然如果是boolean ,然后 D , 一个 distributive conditional type将成为联合 S[] | S ,并且您应该被允许分配 string到那个。所以没有合理的方法来分配 "test"op应该是不安全的。
然而,编译器无法验证这一点。它固执地离开IsMulti一个人,不会让你分配任何东西给D因为它推迟了评估。如果有一些支持的方法来缩小类型参数,或者验证泛型条件类型的可分配性,那就太好了。目前,真的没有。上面链接的 GitHub 问题是一个改进此问题的功能请求,并且有许多相关请求可能会有所帮助(例如,microsoft/TypeScript#27808 可以将 IsMulti 限制为完全 true 或完全 false ,大概然后if (!isMulti) 会将以前的通用类型 IsMulti 缩小到特定类型 false ,并且 D 将被急切地评估)。您可以解决这些问题并给他们一个 👍,但短期内这里会发生任何事情并不明显。

相反,在这种你比编译器更了解类型的情况下,你可以使用 type assertion抑制可分配性错误:
export const t = <IsMulti extends boolean = false>(isMulti: IsMulti): void => {
  const value = 'test';
  type S = string;
  type D = IsMulti extends true ? S[] : S;
  if (!isMulti) {
    const op = value as D; // okay
    console.log(op);
  }
};
通过写 value as D你告诉编译器你知道 value绝对是 D 类型,即使编译器不能。这允许程序无错误地编译。请注意,这不是魔术,并且通过执行类型断言,您可以从编译器中承担一些类型安全的责任。如果你犯了一个错误或对编译器撒谎,它不能总是捕获它:
if (!isMulti) {
  const op = ["oopsie"] as D; // still okay
  console.log(op);
}
所以要小心!
Playground link to code

关于javascript - typescript:从条件类型派生类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71018294/

相关文章:

javascript - 如何获取es6类实例的所有函数

javascript - 如何在开始上传之前获取所有图像文件名?

Android 按下了数组中的哪个按钮索引

arrays - 在 Scala 中检索多维数组中有界元素的最大索引

ReactJS 和 Typescript : refers to a value, 但在此处用作类型 (TS2749)

javascript - $.递延 : How to detect when every promise has been executed

javascript - 数据表 - 请求的未知参数

php - 将十六进制值的字符串转换为 PHP 中 boolean 值的数组

typescript - 在函数中使用条件类型

javascript - 多次调用 sagaMiddleware.run 是否安全?