title: What’s the difference between definite assignment assertion and ambient declaration?
body: <p>When asserting that a field is definitely initialized in a class, what’s the difference between <code>!</code> (exclamation point, definite assignment assertion) and the <code>declare</code> modifier?</p>
  <p>The following code is an error in strict mode since TS doesn’t know for sure that the field has been initialized.</p>
  <pre class="lang-js prettyprint-override"><code>class Person {
      name: string; // Error: Property 'name' has no initializer and is not definitely assigned in the constructor.
  }
  </code></pre>
  <p>I’ve seen 2 ways of handling this:</p>
  <ol>
  <li>Definite assignment assertion:
  <pre class="lang-js prettyprint-override"><code>class Person {
      name!: string;
  }
  </code></pre>
  </li>
  <li>Ambient declaration:
  <pre class="lang-js prettyprint-override"><code>class Person {
      declare name: string;
  }
  </code></pre>
  </li>
  </ol>
  <p>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 <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#the-usedefineforclassfields-flag-and-the-declare-property-modifier" rel="noreferrer">ambient declaration</a> (released in v3.7) simply outdate <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#definite-assignment-assertions" rel="noreferrer">definite assignment</a> (released in v2.7)? Should <code>declare</code> be used instead of <code>!</code> whenever possible?</p>