明确赋值断言和环境声明之间有什么区别?
What’s the difference between definite assignment assertion and ambient declaration?
在class中断言一个字段被明确初始化时,!
(感叹号,明确赋值断言)和declare
修饰符有什么区别?
以下代码在严格模式下是错误的,因为 TS 不确定该字段是否已初始化。
class Person {
name: string; // Error: Property 'name' has no initializer and is not definitely assigned in the constructor.
}
我见过两种处理方法:
- 明确赋值断言:
class Person {
name!: string;
}
- 环境声明:
class Person {
declare name: string;
}
我看不出这两种技术之间的区别。它们都可以修复错误,它们都不会发出代码,它们都不允许初始化器。 ambient declaration (released in v3.7) simply outdate definite assignment(在v2.7中发布)吗?是否应尽可能使用 declare
而不是 !
?
Declare 主要用于在使用类型系统时模拟值。在生产代码中,它很少被使用。
declare name: string;
这对编译器说:
"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."
declare
关键字通常用于类型定义文件中,这些文件为 Typescript 无法从中获取类型信息的文件(例如纯 JS 文件)提供类型。因此,如果我正在阅读您的代码,我会假设 name
正在从某处的某个 JS 文件中进行猴子修补,而您在这里注意到了这一点。
我错了。
name!: string;
这对编译器说:
"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
一开始是未定义的,但无论如何都被视为一个字符串。这意味着它必须在这个文件的某个地方设置,只是可能不在构造函数中。
根据你所说的,我的这些假设是正确的。
实际上,结果几乎相同。在这两种情况下,您都有一个字符串 属性 ,您永远不必实际初始化。但是,我认为 name!: string
对实际发生的事情要清楚得多。
此外,declare
从不 发出代码。它使某些东西只存在于类型系统中。 (感谢@NoelDeMartin 提到这个)
class Foo {
bar!: string;
declare baz: string;
}
let bar: string
declare let baz: string
编译为:
class Foo {
constructor() {
Object.defineProperty(this, "bar", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
}
}
let bar;
请注意,输出中完全没有 baz
。
最后,我不得不提一下,您可能应该重构您的代码,以便您可以在构造函数中分配 属性。这两种方法都不是类型安全的,因为您可能会将未初始化的值视为 string
,如果发生这种情况可能会导致崩溃。
在class中断言一个字段被明确初始化时,!
(感叹号,明确赋值断言)和declare
修饰符有什么区别?
以下代码在严格模式下是错误的,因为 TS 不确定该字段是否已初始化。
class Person {
name: string; // Error: Property 'name' has no initializer and is not definitely assigned in the constructor.
}
我见过两种处理方法:
- 明确赋值断言:
class Person { name!: string; }
- 环境声明:
class Person { declare name: string; }
我看不出这两种技术之间的区别。它们都可以修复错误,它们都不会发出代码,它们都不允许初始化器。 ambient declaration (released in v3.7) simply outdate definite assignment(在v2.7中发布)吗?是否应尽可能使用 declare
而不是 !
?
Declare 主要用于在使用类型系统时模拟值。在生产代码中,它很少被使用。
declare name: string;
这对编译器说:
"There is a property called
name
of typestring
. I shouldn't have to prove to you thatname
actually exists, but I want to use it anyway."
declare
关键字通常用于类型定义文件中,这些文件为 Typescript 无法从中获取类型信息的文件(例如纯 JS 文件)提供类型。因此,如果我正在阅读您的代码,我会假设 name
正在从某处的某个 JS 文件中进行猴子修补,而您在这里注意到了这一点。
我错了。
name!: string;
这对编译器说:
"There is a property called
name
with a type ofstring | undefined
. It starts with a value ofundefined
. But every time I get or set that property, I want to treat it as typestring
."
使用这种形式,任何阅读代码的人都清楚,name
一开始是未定义的,但无论如何都被视为一个字符串。这意味着它必须在这个文件的某个地方设置,只是可能不在构造函数中。
根据你所说的,我的这些假设是正确的。
实际上,结果几乎相同。在这两种情况下,您都有一个字符串 属性 ,您永远不必实际初始化。但是,我认为 name!: string
对实际发生的事情要清楚得多。
此外,declare
从不 发出代码。它使某些东西只存在于类型系统中。 (感谢@NoelDeMartin 提到这个)
class Foo {
bar!: string;
declare baz: string;
}
let bar: string
declare let baz: string
编译为:
class Foo {
constructor() {
Object.defineProperty(this, "bar", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
}
}
let bar;
请注意,输出中完全没有 baz
。
最后,我不得不提一下,您可能应该重构您的代码,以便您可以在构造函数中分配 属性。这两种方法都不是类型安全的,因为您可能会将未初始化的值视为 string
,如果发生这种情况可能会导致崩溃。