代码之家  ›  专栏  ›  技术社区  ›  Michael Zlatkovsky

为什么强制转换的类型安全性不如显式类型化变量声明?

  •  0
  • Michael Zlatkovsky  · 技术社区  · 7 年前

    我喜欢打字安全,这就是为什么我喜欢打字脚本。

    声明额外的变量以获得我需要的类型安全性。


    更新示例:

    [object Object] ):

    如果我只是在这里编写这段代码,它不会阻止我意外地传入一个对象 somethingElse

    如果我为 urlParts 并将其键入 string[] ,我可以预防该问题:

    const baseUrl = "https://stackoverflow.com/"
    const somethingElse = { not: "a string" };
    const urlParts: string[] = [baseUrl, somethingElse];
    window.location.replace(urlParts.join("\n"))
    

    然而,似乎没有一种方法可以让我不创建一个单独的 urlParts

    window.location.replace(([baseUrl, somethingElse] as string[]).join("\n"))
    window.location.replace((<string[]>[baseUrl, somethingElse]).join("\n"))
    

    我发现避免创建变量的唯一方法是将结果内联为 荒谬的解决办法:

    window.location.replace(((): string[] => [baseUrl, somethingElse])().join("\n"))
    


    Experimentation in TS Playground


    这是TypeScript错误/漏洞吗?还是我遗漏了什么?

    我问了几位同事,看看他们有什么想法,

    谢谢

    0 回复  |  直到 7 年前
        1
  •  8
  •   jcalz    7 年前

    Type assertions type annotations 拓宽 表达式的类型是可以安全读取的,只有类型断言允许您 狭窄的

    x 类型 string string | number . 这是因为所有类型的值 一串 而且 字符串|编号 . 所以两者都是 let y: string | number = x x as string | number

    另一方面,如果给你一个变量 y 类型 字符串|编号 是的 将变量视为 更窄的 一串 哪些是 一串 . 所以 let x: string = y 字符串|编号 作为一个 一串 . 但是 y as string 是允许的,因为您告诉编译器您知道的比它知道的多。有时编译器推断出的类型比您能推断的范围更广,如 let y = true ? "a" : 1; . “显然” Y 将是一个 ,但编译器(从TS3.3开始)没有注意到只有三元运算符的真正分支将被计算,因此它推断 对于 Y . 所以你可以断言 是安全的,编译器会相信你。

    此外,如注释中所述,术语“类型断言”优于“类型转换”,通常是因为“类型转换”有时意味着某种运行时效果。TypeScript的类型系统是完全独立的 erased 在运行时,因此只有在设计时类型系统才会执行任何操作。断言是告诉编译器如果无法验证特定表达式是否为特定类型,则不要担心。如果你的断言是正确的,那么一切都很好。如果你的断言是错误的,那么一切都是错误的 似乎 在设计时很好,然后您将收获任何发生在您身上的运行时结果。

    彻底地 不安全的编译器仍然有可能拒绝断言 x as T x 既不比类型窄也不比类型宽 T . 例如,如果您有一个变量 z 你写 z as number unknown 是所有类型的commmon超类型,因此您可以随时编写 z as unknown as number

    还请注意 x作为T 类型断言的语法与 <T> x 语法。有两种写作方式的唯一原因是 angle brackets don't play nicely with JSX .

    好吧,希望这会有帮助;祝你好运


    更新:要以内联方式获得类型注释的安全性,我认为最简单的方法是使用helper函数。这不像你现在的生活那么疯狂,但它是相似的。我是这样做的:

    const ann = <T>(x: T) => x;
    

    功能 ann

    window.location.replace(ann<string[]>([baseUrl, somethingElse]).join("\n"))
    // error on somethingElse, as expected
    

    你觉得这样行吗?

    推荐文章