typescript 确定赋值Assert和环境声明有什么区别?

3df52oht  于 2023-05-01  发布在  TypeScript
关注(0)|答案(1)|浏览(228)

当Assert一个字段在一个类中被明确初始化时,!(感叹号,明确赋值Assert)和declare修饰符有什么区别?
下面的代码在严格模式下是一个错误,因为TS不确定该字段是否已初始化。

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

我看到了两种处理方法:
1.确定赋值Assert:

class Person {
    name!: string;
}

1.环境声明:

class Person {
    declare name: string;
}

我看不出这两种技术之间的区别。它们都能修复错误,都不发出代码,都不允许初始化器。进行环境声明(在v3中发布。7)简单过时的明确赋值(在v2中发布。7)?是否应该尽可能使用declare而不是!

yeotifhr

yeotifhr1#

Declare主要用于在使用类型系统时模拟值。在生产代码中,它很少使用。

declare name: string;

这对编译器说:

  • “有一个名为name的属性,类型为string。我不需要向您证明name确实存在,但无论如何我都想使用它。“*

declare关键字通常用于类型定义文件,这些文件为Typescript无法从中获取类型信息的文件(例如纯JS文件)提供类型。因此,如果我正在阅读您的代码,我会假设name正在从某个JS文件中获取monkey补丁,您在这里注意到了这一点。
我错了。

name!: string;

这对编译器说:

  • “有一个名为name的属性,其类型为string | undefined。它以undefined的值开始。但每次获取或设置该属性时,我都希望将其视为类型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,如果发生这种情况,可能会导致崩溃。

相关问题