编译时断言接口中的可选属性在类中不为 null

Ell*_*tch 5 interface optional-parameters typescript

在 Javascript 中,我喜欢将 an 传递options object给 a constructor ,并用默认值填充我期望的任何缺失属性:

function foo(options) {
   if(options.a == undefined) {
      options.a = 1;
   }
   if(options.b == undefined) {
      options.b = 'hello';
   }
   this.options = options;
}

new foo({a: 10});
Run Code Online (Sandbox Code Playgroud)

尝试在 Typescript 中实现此模式,我有:

interface Options {
    a?: number;
    b?: string;
}

class Foo {
   options: Options;
   constructor(options: Options) {
      if(options.a == undefined) {
         options.a = 1;
      }
      if(options.b == undefined) {
         options.b = 'hello';
      }
      this.options = options;
   }
}
Run Code Online (Sandbox Code Playgroud)

当我optionsclass后面使用时,我知道所有的属性都被定义了。但是,Typescript 不知道这一点,因此此语句会产生错误:

let a:Number = this.options.a; // Argument of type 'number | undefined' is not assignable to parameter of type number.
Run Code Online (Sandbox Code Playgroud)

此外,我不想让 中的代码稍后为该属性class分配null或值:undefined

this.options.a = undefined; // should produce compiler error
Run Code Online (Sandbox Code Playgroud)

有没有办法定义我的类型,以便在不定义两个接口的Options情况下使用时, 的属性不能为空?class Options

例如,我知道我可以制作另一个interface供内部使用:

interface OptionsSafe {
    a: number;
    b: string;
}

// in Foo constructor
this.options = {
    a: a != undefined ? options.a! : 1,
    b: b != undefined ? options.b! : 'hello'
};
Run Code Online (Sandbox Code Playgroud)

但随后我需要在两个单独的接口中定义选项的属性,并确保它们始终保持同步(如果 Typescript 可以从一个定义生成两个接口,那么这个解决方案会很棒)。

我也不想将所有属性作为单独的可选参数传递,因为

  1. 可以有几十个或更多的选项
  2. 函数参数可能会偏离Options接口,所以我仍然必须保持两个“接口”同步。

cas*_*ber 5

Partial一种选择是使用Typescript 提供的内置类型。对于您来说,这可能太接近“定义两个Options接口”,但无论如何我都会向您展示我的意思。

Typescript 提供了一个内置类型Partial,定义为type Partial<T> = {[P in keyof T]?: T[P]}.

这意味着您可以做的只是定义Options包含所有成员的接口,但将其部分版本用于构造函数。像这样:

interface Options {
    a: number;
    b: string;
}

class Foo {
   options: Options;
   constructor(options: Partial<Options>) {
      const defaultOptions = {
          a: 1,
          b: 'hello'
      };

      this.options = Object.assign(defaultOptions, options);
   }
}
Run Code Online (Sandbox Code Playgroud)

为了让 Typescript 正确推断您已经获得了对象的所有必要属性,您需要从if您使用的语句逻辑转向类似于上面的逻辑。