More Special Declaration Types in JS
#21974
In 2.7, we started treating variables initialized with empty object literals as namespaces in JS files.
var foo = {};
foo.x = 10
foo.y = 20;
Now you can omit the var
app = {};
app.C = function() {
// ...
}
Also allows IIFEs to be namespaces.
var C = (function () {
function C(n) {
this.p = n;
}
return C;
})();
[[Daniel: I'm going to stop here because you can just read the PR writeup.]]
- We need to put these together in one document.
- Why do we do this in JavaScript and not in TypeScript?
- We're supposed to be a superset.
- What about declaration emit?
- Would we serialize using the TS-specific syntax?
- Should we only recognize this with
var declarations as opposed to just consts?
- Can always re-assign to a
var.
- It is currently still awkward to transition from a
.js file to a .ts file.
- You switch to
.ts and you become temporarily untyped even if you want
- What about a mode that enables these constructs in
.ts?
- What about if
allowJs just permitted this?
- How do you disable the behavior though?
- When do you want to disable it?
- When you want to start writing super-strict
.ts in existing JS code.
- "I'm worried about having too many flags"
- What about initializing fields in a class?
- TypeScript requires fields to be declared up-front
- How do you prevent misspelled properties?
- Conclusion: we will think harder!
The unknown type
#10715
- Prototyped it as a new primitive type.
- Doesn't have to be a new primitive type.
- In non-strict mode, everything is assignable to
{} except for void.
- In
strictNullChecks, you get a problem because you have to write {} | null | undefined; it's annoying.
- Can just write an alias!
- That way you can still get narrowing; check
!= null and then you'll be able to call toString() on it.
- Problem: If we put this in
lib.d.ts, you can run with skipLibCheck and TypeScript won't always print that out because it won't have seen the alias.
- We could fix this in
strictNullChecks mode by forcing the checker to resolve this.
- But then in non-
strictNullChecks mode,
- What about failed type argument inference?
- Could default to
unknown instead of {}?
- But not clear you get a lot of value from that.
- Could also not do anything.
- Problem: implies you'd need to change the constraint; implementations of generic functions currently make the assumption that type parameters will not be
null or undefined (constraint is implicitly {}).
- We want it highlighted as a keyword though...
- So should it be an alias?
- Open questions
- Does
x > 0 imply narrowing?
if (x) narrows to {}?
if (!x) narrows to {} | null | undefined?
- Yes.
- Currently no?
- @chancancode reported this and we said "ehhhh"
- What does
{ [s: string]: unknown } mean?
- Problems with dictionaries becoming assignable to anything.
- What's the type of
unknown | T?
- Question becomes "should we collapse unions containing
{}?
- But then you lose the contextual type in some cases, which would break a bunch of React code.
- We need to see what people are doing on DefinitelyTyped and see what the intent is there.
- Should write a TSLint rule to track them down.
- What's the type of
s!?
{}
- (as opposed to
object | string | number | boolean).
Distribute keyof on intersections
#22300
This now works as expected!
type X<A, B> = Record<A, object> & Record<B, object>
// keyof A | keyof B
type Y<A, B> = keyof X<A, B>
More Special Declaration Types in JS
#21974
In 2.7, we started treating variables initialized with empty object literals as namespaces in JS files.
Now you can omit the
varAlso allows IIFEs to be namespaces.
[[Daniel: I'm going to stop here because you can just read the PR writeup.]]
vardeclarations as opposed to justconsts?var..jsfile to a.tsfile..tsand you become temporarily untyped even if you want.ts?allowJsjust permitted this?.tsin existing JS code.The
unknowntype#10715
{}except forvoid.strictNullChecks, you get a problem because you have to write{} | null | undefined; it's annoying.!= nulland then you'll be able to calltoString()on it.lib.d.ts, you can run withskipLibCheckand TypeScript won't always print that out because it won't have seen the alias.strictNullChecksmode by forcing the checker to resolve this.strictNullChecksmode,unknowninstead of{}?nullorundefined(constraint is implicitly{}).x > 0imply narrowing?if (x)narrows to{}?if (!x)narrows to{} | null | undefined?{ [s: string]: unknown }mean?unknown | T?{}?s!?{}object | string | number | boolean).Distribute
keyofon intersections#22300
This now works as expected!