Description
Making Type Error Elaboration More Consistent
- 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
-
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
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 betweentypesVersions
, 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.
- PR also has support for
-
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 andawait
?- 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.
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
.
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 toDataOrNull<string>
, we try to just ask "isstring | null
assignable tostring
?" and answer "no".
- When we ask if
-
One idea: give people a new opt-out for variance calculation?
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?
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?
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.