Repository: TypeScript
Issue: Design Meeting Notes, 7/12/2024
Labels: Design Notes

# Making Type Error Elaboration More Consistent

https://github.com/microsoft/TypeScript/pull/58859

* Problem: you may get a different error elaboration in different locations depending on the order in which a program is checked.
    * There are various reasons for this,  with the class of differences we're concerned about here, but we try to avoid reporting the full context if you've already seen it.
* The main reason we're focusing on this is region-based diagnostics. If you first check statements in the middle of the file, it is weird to get a different level of error detail than top-down checking.
* In this PR, every time we report a type error, we will now provide the full elaboration.

# Deferred Parameters and Control Flow Analysis for Function Expression Arguments

https://github.com/microsoft/TypeScript/pull/58729

* Feel it is a valuable fix for a long-standing problem.
* Core idea is to assume that callback function expressions are possibly called, and to factor that into the control flow analysis of variables used afterwards.
* Means that in cases like

  ```ts
  let x: number | undefined;
  x = 42;
  someArray.forEach(() => { x = undefined; });
  x++; // Should be an error. Was not previously, is an error with this PR.
  ```

  now correctly fail to type-check.
* To opt out, the idea is to introduce a `deferred` modifier; but there's a compatibility problem with all the tools in the ecosystem understanding that. Declaration files will need to introduce it and split between `typesVersions`, existing code may need an annotation even in `.ts` files.
    * PR also has support for `/** @deferred */` JSDoc comment that is understood in `.ts` files - not just `.js` files.
* Also a question of a new parameter modifier being possibly in conflict with JavaScript.
    * We don't see one, but it might be worth reaching out to the committee to better understand concerns.
* What's the relationship between a `deferred` callback and `await`?
    * It doesn't really factor in; we don't analyze deferred callbacks other than at the use-site.
* How does declaration emit work for the JSDoc tag?
    * What you write is what you get.
* What happens when a library is not upgraded to use `deferred`?
    * You can just use a type assertion to the expected type to opt out.
    * Alternatively, and maybe more preferred, is to write a function that takes a deferred callback and returns it.

      ```ts
      function deferred<F extends (...args: never[]) => unknown>(deferred callback: F): F {
          return callback;
      }
      ```
* We want to make sure that we're not missing anything. Will do the work to get Node.js and lib.d.ts/DOM libraries to have `deferred`.

#  

```ts
type DataOrNull<T> = {
    data: T | null;
};

declare function check(s: DataOrNull<string>): void;

declare let foo: DataOrNull<string | null>;
check(foo); // Error?
```

* We "smartly" infer that `T` is covariant (please disregard the soundness aspect here).
    * When we ask if `DataOrNull<string | null>` is assignable to `DataOrNull<string>`, we try to just ask "is `string | null` assignable to `string`?" and answer "no".
* One idea: give people a new opt-out for variance calculation?

  ```ts
  type DataOrNull<unmeasurable T> = {
      data: T | null;
  };
  ```

* "Unmeasurable" is the concept we use internally to say "this type parameter must always be checked with respect to the structure of the containing type".
* What do we name this?

  ```ts
  type DataOrNull<sus T> = {
      data: T | null;
  };
  ```
* `structural`?
* `linear`?
* `inconsistent`?
* `nonvariant`
* Could we infer this better?
    * The pattern is common, and if we don't infer some variance in these scenarios, things are likely to get quite a bit slower.
* Isn't a similar problem going to come up with libraries prioritizing correctness?
    * Unmeasurable variance is pretty infectious with type parameters. A type reference that takes a type variable for an unreliable type parameter makes the type variable also unreliable with respect to its containing type.
* Could view this as "unreliable" - another internal view of type parameters, where they might have a variance, but uses the structural fallback.
* What about this on the use-site?

  ```ts
  declare let foo: DataOrNull<structural string>;
  ```
    * Hard to think about what that means/explain to developers.
* There are hacks to induce unreliable variance. @RyanCavanaugh will post this.