Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/flash/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 为什么强制转换的类型安全性不如显式类型化变量声明?_Typescript - Fatal编程技术网

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

Typescript 为什么强制转换的类型安全性不如显式类型化变量声明?,typescript,Typescript,我喜欢打字安全,这就是为什么我喜欢打字脚本 然而,我发现在某些情况下,我最终不得不明确地 声明额外的变量以获得我需要的类型安全性 更新示例: 假设我想调用字符串数组中的.join,我真的想确保它是字符串数组,而不是对象数组,它们最终会作为[object]输出: 如果我只是在这里执行此代码,它不会阻止我意外地为某些事情传入对象。例如: 如果我为urlParts创建一个数组并将其键入字符串[],我可以防止出现以下问题: const baseUrl = "https://stackoverflow.

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

然而,我发现在某些情况下,我最终不得不明确地 声明额外的变量以获得我需要的类型安全性

更新示例:

假设我想调用字符串数组中的.join,我真的想确保它是字符串数组,而不是对象数组,它们最终会作为[object]输出:

如果我只是在这里执行此代码,它不会阻止我意外地为某些事情传入对象。例如:

如果我为urlParts创建一个数组并将其键入字符串[],我可以防止出现以下问题:

const baseUrl = "https://stackoverflow.com/"
const somethingElse = { not: "a string" };
const urlParts: string[] = [baseUrl, somethingElse];
window.location.replace(urlParts.join("\n"))
然而,如果不创建一个单独的urlParts变量,我似乎无法做到这一点,而我一直希望避免创建一个单独的urlParts变量。例如,通过以下方式之一:

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

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

我问了几位同事,看看他们有什么想法, 但我们无法找到如何获得更严格的类型

谢谢

的安全性不如,因为注释和断言都允许您扩展表达式的类型,这对读取是安全的,但只有类型断言允许您缩小表达式的类型,这对读取是不安全的。编译器允许您这样做,因为您断言这是真的

例如。。。假设给您一个字符串类型的变量x。如果您只是读取该变量的值,那么可以安全地将该变量视为更宽的类型,如string | number。这是因为string类型的所有值也是string | number类型的值。因此都让y:string | number=x和x作为string | number是有效的,因为编译器可以验证这些表达式的有效性

另一方面,如果给您一个类型为string | number的变量y,则将该变量视为更窄的字符串类型是不安全的。这是因为字符串| number类型的值不是字符串类型的值。因此,让x:string=y将给出一个编译器错误;编译器知道将字符串|数字视为字符串是不安全的。但是y作为字符串是允许的,因为你告诉编译器你知道的比它知道的多。有时编译器会推断出比您能推断出的更宽的类型,如let y=true?a:1;。很明显,y将是一个字符串,但编译器在TS3.3中没有注意到只有三元运算符的真正分支将被计算,因此它推断y的字符串|编号。所以您可以断言y,因为字符串是安全的,编译器会相信您

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

类型断言并不是完全不安全的;如果为x推断的类型既不比T类型窄也不比T类型宽,编译器仍有可能拒绝将x断言为T。例如,如果您有一个字符串类型的变量z,并且您将z作为数字写入,编译器仍会警告您。在这种情况下,您仍然可以强制编译器提交,方法是注意,在继续之前,您始终可以先扩展到公共超类型或缩小到公共子类型。该类型是所有类型的commmon超类型,因此您可以始终将z写为与number一样未知的值,并消除编译器可能提出的任何异议

还要注意,类型断言的x as T语法与x语法的作用完全相同。有两种写作方式的唯一原因是因为

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

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

const ann = <T>(x: T) => x;
这对您来说足够好吗?

的安全性不如它,因为注释和断言都允许您扩展表达式的类型,这对读取是安全的,但只有类型断言允许您缩小表达式的类型,这对读取是不安全的。编译器允许您这样做,因为您断言这是真的

例如。。。假设给您一个字符串类型的变量x。如果您只是读取该变量的值,那么可以安全地将该变量视为更宽的类型,如string | number。这是因为string类型的所有值也是string | number类型的值。所以都让y:string | number=x,x作为str ing |数字是有效的,因为编译器可以验证这些表达式的有效性

另一方面,如果给您一个类型为string | number的变量y,则将该变量视为更窄的字符串类型是不安全的。这是因为字符串| number类型的值不是字符串类型的值。因此,让x:string=y将给出一个编译器错误;编译器知道将字符串|数字视为字符串是不安全的。但是y作为字符串是允许的,因为你告诉编译器你知道的比它知道的多。有时编译器会推断出比您能推断出的更宽的类型,如let y=true?a:1;。很明显,y将是一个字符串,但编译器在TS3.3中没有注意到只有三元运算符的真正分支将被计算,因此它推断y的字符串|编号。所以您可以断言y,因为字符串是安全的,编译器会相信您

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

类型断言并不是完全不安全的;如果为x推断的类型既不比T类型窄也不比T类型宽,编译器仍有可能拒绝将x断言为T。例如,如果您有一个字符串类型的变量z,并且您将z作为数字写入,编译器仍会警告您。在这种情况下,您仍然可以强制编译器提交,方法是注意,在继续之前,您始终可以先扩展到公共超类型或缩小到公共子类型。该类型是所有类型的commmon超类型,因此您可以始终将z写为与number一样未知的值,并消除编译器可能提出的任何异议

还要注意,类型断言的x as T语法与x语法的作用完全相同。有两种写作方式的唯一原因是因为

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

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

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

这对您来说足够好吗?

作为数字[],或者不检查数组是否只包含数字,它会向编译器坚持它包含数字。你绕过了常规检查。[hi,6]。forEachitem=>item.toExponential5将显示错误,因为推断的类型是number | string。它们不是强制类型转换。@jonrsharpe,你完全正确,在我的原始示例中,如果我可以让编译器只执行其工作,那么我强制类型转换为number[]是毫无意义的。请参阅我的完全更新的示例,该示例借鉴了我遇到它的一个真实示例。如果不检查数组是否只包含数字,它会向编译器坚持它包含数字。你绕过了常规检查。[hi,6]。forEachitem=>item.toExponential5将显示错误,因为推断的类型是number | string。它们不是强制类型转换。@jonrsharpe,你完全正确,在我的原始示例中,如果我可以让编译器只执行其工作,那么我强制类型转换为number[]是毫无意义的。请参阅我的完全更新的示例,它借鉴了我遇到的一个真实示例。感谢您的回复。我用一个更好的例子更新了我的问题,说明了今天缺乏类型安全性给我带来的麻烦。我想我的问题仍然是:有没有任何方法可以在不声明一个全新变量的情况下进行内联类型断言?我喜欢这种解决方法,这使它更加合理。我会开始用它的。您认为值得向TypeScript推荐这样的用例,使其成为更合适的特性吗?理想情况下,这感觉像是将内置到语言中的东西,而不是需要为其编写实用程序的东西,也不是对运行时有影响的东西,无论多么小……无论如何,感谢您的帮助!将您的答案标记为已接受答案。对于阅读本文的任何人:听起来,感谢您的回复,我们正在跟踪相同的请求/需求。我用一个更好的例子更新了我的问题,说明了今天缺乏类型安全性给我带来的麻烦。我想我的问题仍然是:有没有任何方法可以在不声明一个全新变量的情况下进行内联类型断言?我喜欢这种解决方法,这使它更加合理。我会开始用它的。您认为值得向TypeScript推荐这样的用例,使其成为更合适的特性吗?理想情况下,这感觉像是语言中内置的东西,而不是需要wr的东西
这是一个对运行时没有影响的工具,不管它有多小……无论如何,谢谢你的帮助!将您的答案标记为已接受的答案。对于阅读此内容的任何人:听起来您正在跟踪相同的请求/需求
window.location.replace(ann<string[]>([baseUrl, somethingElse]).join("\n"))
// error on somethingElse, as expected