との差 '!' および「?」TypeScriptで

Aug 21 2020
Class Employee {
  firstName: string;
  lastName!: string;
  middleName?: string;
}

Employeeクラスのこれらの3つの異なるフィールドの違いは何ですか?

実例

回答

3 T.J.Crowder Aug 21 2020 at 19:39

?その位置でマークプロパティオプション。

!その位置には、明確な割り当て表明。これは、null以外のアサーション演算子の宣言レベルのバージョンのようなものですが、式ではなくプロパティ(変数でも使用できます)で使用されます。

この例には、2つ(またはおそらく3つ)のエラーがあります。

  1. Classする必要がありclassます; JavaScriptとTypeScriptでは大文字と小文字が区別されます。

  2. 初期化子firstName(または無条件に割り当てるコンストラクター)が必要です。

  3. !上には、lastName活字体伝えlastName間違いなくあなたが取得しているエラーの種類を抑制し、割り当てられますfirstNameが、(この例では)何も実際には行われません使用していることを割り当て!が約束することは、あなたがやっていることを確認するために知って活字体を。

編集:後でリンクしたコードは、上記の#1と#2を扱いますが、#3は扱いません。TypeScriptlastNameは、割り当てられていないことを警告せず、値が文字列であると想定しますが、実際には文字列がないため、値を読み取るとundefined。になります。

1 axiac Aug 21 2020 at 19:24

それらはTypeScriptのドキュメントによく隠されています。

?はインターフェイスで説明されており、オプションのプロパティをマークします。

!は明確なアサーション演算子です。TypeScriptの分析で検出できない場合でも、プロパティが設定されている(nullまたはではないundefined)ことをコンパイラに通知します。


ところで、ClassTypeScriptまたはJavaScriptキーワードではなく、その位置でエラーが発生します。クラスを宣言するためのキーワードはclassです。活字体とJavaScriptの識別子とキーワードは大文字と小文字が区別されます(Classclass異なるものです)。

1 SherifElmetainy Aug 23 2020 at 23:12

コンパイラオプションがある場合 strictNullChecks: false

あなたが持っている場合はstrictNullChecks: false、あなたの中でtsconfig.json、彼らは持つので、全く同じでstrictNullChecks、すべてのフィールドがNULLまたは有効な値として未定義ことを無効にする手段を。

コンパイラオプションがある場合 strictNullChecks: true

class Employee {
   firstName: string;
   lastName!: string;
   middleName?: string;
}

firstName: stringつまり、でfirstNameある必要がありstringます。nullまたはundefinedfirstNameの有効な値ではありません。

すべてのフィールドにデフォルト値が設定さundefinedれ、エラーが発生しますProperty 'firstName' has no initializer and is not definitely assigned in constructor

エラーを消音するには、宣言をに変更するかfirstName: string = 'Some default value'、コンストラクターを追加して、コンストラクターでその値を割り当てる必要があります。

constructor() {
    this.firstName = 'some default value';
}

さあ!構文。lastName!: stringように構文が似ているlastName: stringという点で、それは基本的に唯一と言っているstringだけ許さタイプです。nullundefinedは許可されていません。しかし、それは明確な割り当てエラーについてコンパイラを沈黙させます。次のコードがあるとしましょう。

クラス従業員{firstName:文字列; lastName !:文字列; ミドルネーム?:文字列;

  constructor() {
      // This will silence the compiler about first name not initialized
      this.firstName = 'some default value';
      // The compiler cannot tell that lastName is assigned in init() function
      this.init();
  }
  
  private init(): void {
      this.lastName = 'some default value';
  }
}

前のコードでlastNameは、は呼び出しconstructorを介して確実に割り当てられていthis.init()ます。しかし、コンパイラはそれを知ることができません。したがって、!を追加します。基本的にはコンパイラに「黙って、自分が何をしているのか知っている」と言っています。コードの正確さを保証するのはあなた次第です。

middleName?: string構文について。これはmiddleName: string | undefined;とまったく同じです。すべての値のデフォルト値はundefinedであるため、コンパイラはmiddleName割り当てられていないことを文句を言いません。