简体   繁体   English

明确赋值断言和环境声明有什么区别?

[英]What’s the difference between definite assignment assertion and ambient declaration?

When asserting that a field is definitely initialized in a class, what's the difference between !当断言一个字段在 class 中肯定被初始化时,有什么区别! (exclamation point, definite assignment assertion) and the declare modifier? (感叹号,明确的赋值断言)和declare修饰符?

The following code is an error in strict mode since TS doesn't know for sure that the field has been initialized.以下代码是严格模式下的错误,因为 TS 不确定该字段是否已初始化。

class Person {
    name: string; // Error: Property 'name' has no initializer and is not definitely assigned in the constructor.
}

I've seen 2 ways of handling this:我见过两种处理方法:

  1. Definite assignment assertion:确定赋值断言:
     class Person { name:; string; }
  2. Ambient declaration:环境声明:
     class Person { declare name: string; }

I can't see the difference between these two techniques.我看不出这两种技术之间的区别。 They both cure the error, they both don't emit code, and they both don't allow initializers.它们都解决了错误,它们都不发出代码,并且它们都不允许初始化程序。 Does ambient declaration (released in v3.7) simply outdate definite assignment (released in v2.7)? 环境声明(在 v3.7 中发布)是否简单地过时明确的分配(在 v2.7 中发布)? Should declare be used instead of !应该declare使用而不是! whenever possible?只要有可能?

declare name: string;

This says to the compiler:这对编译器说:

"There is a property called name of type string . I shouldn't have to prove to you that name actually exists, but I want to use it anyway." “有一个名为namestring类型的属性。我不应该向你证明name确实存在,但我还是想使用它。”

The declare keyword is typically used in type definition files that provide typings for files that Typescript cannot get type information from (such as plain JS files). declare关键字通常用于类型定义文件,为 Typescript 无法从中获取类型信息的文件(例如纯 JS 文件)提供类型。 So if I was reading your code, I would assume that name is getting monkey patched in from some JS file somewhere, and you are noting that here.因此,如果我正在阅读您的代码,我会假设该name正在从某处的某个 JS 文件中被猴子修补,而您在这里注意到了这一点。

I would be incorrect.我会不正确。


name!: string;

This says to the compiler:这对编译器说:

"There is a property called name with a type of string | undefined . It starts with a value of undefined . But every time I get or set that property, I want to treat it as type string ." “有一个名为name的属性,其类型为string | undefined 。它以undefined的值开头。但每次获取或设置该属性时,我都想将其视为string类型。”

Using this form it's clear to anyone reading the code that name is undefined at first, but is treated like a string anyway.使用这种形式,任何阅读代码的人都可以清楚地看到, name最初是未定义的,但无论如何都被视为字符串。 That means it must be set in this file somewhere, just probably not in the constructor.这意味着它必须在这个文件的某个地方设置,只是可能不在构造函数中。

From what you are saying, I would be correct in those assumptions.从你所说的来看,我在这些假设中是正确的。


In practice the result is identical.在实践中,结果是相同的。 In both cases you have a string property that you never have to actually initialize.在这两种情况下,您都有一个不需要实际初始化的字符串属性。 However, I would argue that the name:: string is far more clear about what is actually going on.但是,我认为name:: string更清楚地说明了实际发生的情况。


Lastly though, I have to mention, you should probably just refactor your code so that you can assign the property in the constructor.最后,我不得不提一下,你可能应该重构你的代码,以便你可以在构造函数中分配属性。 Both those methods are not as type safe since you could potentially treat an uninitialized value as a string , which will likely cause a crash if it happens.这两种方法都不是类型安全的,因为您可能会将未初始化的值视为string ,如果发生这种情况可能会导致崩溃。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM