* Set-only accessors spread to undefined
Previously they were skipped. The runtime behaviour is to create a
property of type undefined, unlike (for example) spreading numbers or
other primitives. So now spreading a set-only accessor creates a
property of type undefined:
```ts
const o: { foo: undefined } = { ...{ set foo(v: number) { } } }
```
Notably, `o.foo: undefined` not `number`.
Fixes#26337
* Fix isSpreadableProperty oversimplification
* Do not merge commonsjs exports onto an alias
getCommonJSExportEquals merges export assignments and export property
assignments. Something like this, which has no equivalent structure in
TS:
```js
module.exports = function() { }
module.exports.expando = 1
```
However, it is sometimes called with an alias, when its
parent, resolveExternalModuleSymbol, is called with dontResolveAlias:
true, and when the initialiser of the export assignment is an alias:
```js
function alias() { }
module.exports = alias
module.exports.expando = 1
```
In this case, (1) the actual value `alias` will have already merged in a
previous call to getCommonJSExportEquals and
(2) getTypeOfSymbol will follow the alias symbol to get the right type.
So getCommonJSExportEquals should do nothing in this case.
This bug manifests in the code for dynamic imports, which calls
getTypeOfSymbol on the incorrectly merged alias, which now has enough
value flags--Function, for example--to take the wrong branch and
subsequently crash.
* Update baselines
* Obey the excludeArgument parameter when checking JSX signature validity
* Fix conditional type extending any contextual types and accept baselines
* use flag check to also drop unknown from comparison for the same reason
* Slight refinement - make an intersection to ensure parameter constraints flow through contextual types when instantiated
* Format ternary more nicely
* Add new special assignment kinds for recognizing Object.defineProperty calls
* Add support for prototype assignments, fix nits
* Fix code review comments
* Add test documenting behavior in a few more odd scenarios
In JS, when you assign `module.exports = exports` and the entire module is
wrapped in an IIFE, the resulting `export=` symbol, after following
aliases, is the module itself. This results in trying to merge the
file's exports with itself inside `getCommonJsExportEquals`, since it
thinks that it has found new exports, possibly in an object literal,
that need to be merged with the file's exports.
For example:
```js
(function() {
exports.a = 1
module.exports = exports
})()
```
1. Merge enum with expando.
2. Merge enum member with property assignment.
3. Merge interface-declared method declaration with
prototype-property-assignment method declaration.
The reason that the enum merges crash is that getTypeOfSymbol assumes
that symbol flags are (basically) mutually exclusive. This assumption is
shredded, badly, for JS merges.
One fix is to drop the assumption of exclusivity and instead order cases
by least to most likely. This has the highest chance of working, but is
also slow, since you would prefer to order cases by most likely *first*,
not *last*.
The other fix, which is what I did here, is to add a last-chance
re-dispatch at the bottom of
`getTypeOfVariableOrParameterOrPropertyWorker`. This dispatch uses the
valueDeclaration instead of the symbol flags.
* Unify JSX Call Checking Codepaths
* Add tests for fixed issues
* Fix lint, move all error checking into the only-run-once resolveSignature call
* Remove unused (unreachable?) code path
* Consolidate a little more duplicated logic into signature checking
* Fix#19775 a bit more
* Cosmetic changes from CR
* Add helpers that understand constructor functions
* getEffectiveConstructSignatures gets construct signatures from type, and
call signatures from constructor functions if there are no construct
signatures.
* getEffectiveConstructSignatureReturnType gets the "JS Class type" for
constructor functions, and the return type of signatures for all other
declarations.
This is a first step toward making constructor functions have construct
signatures instead of call signatures, which will also contribute to
fixing instantiation of generic constructor functions, which is basically
broken right now.
Note that the baselines *improve* but, because of the previously
mentioned generic problem, are still not correct. Construct signatures
for constructor functions and generic constructor functions turns out to
be an intertwined problem.
* Correct correct originalBaseType
And, for now, return anyType for generic constructor functions used as
base types. Don't give an incorrect error based on the function's return
type, which is usually void.
* Add error examples to tests
* Add construct signatures instead of getEffective* functions
* Fix typo in baseline
* Remove pesky newline
I thought I got rid of it!
* Test of constructor tag on object literal method
It doesn't work, and shouldn't in the future, because it's a runtime
error.
The ad-hoc name resolution rule for `exports` forgets to check the
requested meaning. When `getTypeReferenceType` calls`
resolveTypeReferenceName` with `Type` only in order to give an error
when the program uses a value like a type, it is incorrectly able to
resolve `exports` instead of producing an error. Then this incorrect
symbol gets treated like an alias, which it isn't, causing the assert.
The fix, for now, is to make resolution of `exports` check the requested
meaning so that it only resolves when `Value` is requested. This makes
the above code an error ("Cannot use the namespace 'exports' as a
type."), but I think this is fine for a bug fix. We can decide later if
`exports` should behave like other expandos and be a legal type
reference.
Note that the name actually does resolve correctly, so JS users will get
the desired completions. They'll just have an error to suppress if they
have checkJs on.
The check for prototype assignment on constructor functions assumes
that the prototype property, if present, comes from an assignment
declaration, such as:
```js
SomeClass.prototype = { /* methods go here */ }
```
In this case, however, when class SomeClass and var SomeClass merge
(because this is allowed), prototype is the synthetic property from
class SomeClass, which has no valueDeclaration.
The fix is to check that prototype has a valueDeclaration before
checking whether the valueDeclaration is in fact a prototype-assignment
declaration.
`@constructor` put on anything incorrectly makes it a JS constructor. This
is a problem for actual constructors, because getJSClassType doesn't
work on actual classes. The fix is to make isJSConstructor require that
its declaration is a function.
JSDoc types references can often be to values, which can often be
circular in ways that types tied to declarations cannot. I decided to
create a separate property on SymbolLinks rather than reusing
declaredType, although I'm not sure that's strictly required.
TypeScript must hoist accessors for super properties when converting
async method bodies to the `__awaiter` pattern for targets before
ES2016.
Previously, TypeScript would reify all property accesses into element
accesses, i.e. convert the property name into a string parameter and
pass it to `super[...]`. That breaks optimizers like Closure Compiler or
Uglify in advanced mode, when property renaming is enabled, as it mixes
quoted and un-quoted property access (`super['x']` vs just `x` at the
declaration site).
This change creates a variable `_superProps` that contains accessors for
each property accessed on super within the async method. This allows
accessing the properties by name (instead of quoted string), which fixes
the quoted/unquoted confusion. The change keeps the generic accessor for
element access statements to match quoting behaviour.
Fixes#21088.
In the binder, unreachable code mistakenly skips the `bindJSDoc` call in
`bindChildrenWorker`, which sets parent pointers. The fix is to call
`bindJSDoc` in the case of unreachable code as well.
I'm surprised we haven't seen more of this; I suspect it's because the
mixed `module.exports=` + `export.foo=` pattern isn't that common.
However, it'll happen any time that the exported symbol is unknown;
getCommonJsExportEquals blithely clones unknownSymbol and proceeds to
stick the `exports.foo=` properties onto it.
This causes problems later, because the compiler checks for
unknownSymbol with `===`. The fix is to not stick properties onto a
clone of unknownSymbol. This makes the correct errors appear and removes
the crash.
* Fix non-toplevel prototype assignment
binder was using the wrong node to lookup the containing class type for
prototype assignment, so it incorrectly put the prototype declaration on
the class' symbol.
This correction to the binder in turn required a change in
getJSClassType in the checker. It now has to look at the "prototype"
property for the prototype instead of looking on the class symbol's exports
(which makes no sense).
* Refactor per PR suggestion
* Fix cross-file merge of assignment decl valueDeclaration
Previously mergeSymbol in the checker always updated valueDeclaration if
target.valueDeclaration was an assignment declaration. The binder only
updates target.valueDeclaration if it is an assignment declaration and
source.valueDeclaration is *not* an assignment declaration. Now the
checker behaves the same way as the binder.
* Update baselines
* Add a fix for #27099
Makes commonjs merge with globals when appropriate.
* Add a separate jsGlobalAugmentations table
Instead of trying to filter these augmentations out of the normal symbol
table of commonjs modules.
* Fix this-type in prototype-assigned object literals
Some cases were missing from tryGetThisTypeAt.
Fixes#26831
* Lookup this in JS only for @constructor+prototype assignments
* Bind non-expando property assignments at toplevel
Previously, only property assignments with expando initialisers were
bound in top-level statements. Now, all property assignments are bound.
This requires a matching change in the checker to make sure that these
assignments remain context sensitive if their valueDeclaration is a
'real' declaration (ie a non assignment-declaration).
* Add baselines for new test
* Skip asterisks after newline when parsing JSDoc types
* Single boolean expression
* Test for parsing and printing multiline function signatures with *
* check for expando initializers in resolveEntityName
when resolving type parameters in a prototype property assignment
declaration. For example, this already works:
```js
/** @template T */
function f(x) { this.x = x }
/** @returns {T} */
f.protototype.m = function () { return this.x }
```
This now works too:
```js
/** @template T */
var f = function (x) { this.x = x }
/** @returns {T} */
f.prototype.m = function () { return this.x }
```
Fixes#26826
* Lookup type parameters on prototype-assignment methods
In the same way that they're looked up on prototype-property methods.
That is, this previously worked:
```js
/** @template T */
function f() { }
/** @param {T} p */
f.prototype.m = function () { }
```
And this now works too:
```js
/** @template T */
function f() { }
f.prototype = {
/** @param {T} p */
m() { }
}
```
Note that the baselines still have errors; I'll file a followup bug for
them.
* Look up types on property assignments too
* Allow JSContainers to merge with namespaces
Expando functions marked with JSContainer previously failed to merge
with namespaces. This change adds JSContainer to ValueModuleExcludes,
allowing this kind of merge.
* Improve symbol flags to fix namespace/expando merging
Calls to bindPropertyAssignment now provide which special assignment
kind they originated from. This allows better symbol flags to be set:
1. Property assignments get the FunctionScopedVariable flag, since they are
equivalent to a `namespace` exporting a `var`.
2. Prototype property assignments get the Method flag if the initialiser
is functionlike, and Property otherwise.
3. Prototype assignments get the flag Property.
(3) is still not entirely correct (it's missing the Prototype flag),
but is what existed previously. I'll try adding the Prototype flag to
see whether it changes any baselines.
* Add cross-file merge test
* Update missed baselines
* Namespace declarations are primary for merging purposes
Also, property-assignments go back to being property declarations, not
function-scoped variable declarations
* Revert unneeded changes
* Revert unneeded changes (in a codefix this time)
* Put JSContainer on all assignment declarations
This allows most of the new special-case merge code to go away. It now
uses the JSContainer special-case code, which already exists.
* Missed comment
* Fix extra newline lint
in object literal methods inside an object literal with a type
annotation.
Note that this does not change:
1. The type of `this` in object literal methods.
2. The fact that this-property assignments are still declarations. They
just don't block contextual typing like most declarations do.
This change is a bit expensive. It first calls getThisContainer, which
walks the tree upward. Then it calls checkThisExpression, which will
usually call getContextualType on the object literal method. If the new
code then returns true, it will proceed to redo much of that work.
Calling checkThisExpression should not cause incorrect circularity
failures; we only have to inspect the shape of the object literal and
not the types of its properties to determine its type.
* Get [type] parameter types from @type tag
Previously only the return type was used in cases like this:
```js
/** @type {<T>(param?: T) => T | undefined} */
function g(param) {
return param;
}
```
Now the type parameters from the type tag are used, and the compiler
gets the type of the parameter by using the position in the signature of
the type tag.
Fixes#25618
* Fix split ifs according to PR comments
The assert is over-optimistic and should be removed until we can parse
every possible thing that people might put in a JSDoc type position.
Fixes#26693
* Declaration emit includes function properties
It does this by printing the type as an object literal type:
```ts
function f() { }
f.p = 1
```
Appears in a d.ts as
```ts
declare var f: {
(): void;
p: number;
}
```
It would also be possible to represent it as a namespace merge. I'm not
sure which is better.
```ts
declare function f(): void;
declare namespace f {
export var p: number;
}
```
In order to avoid a private-name-used error (though I think it was
actually *unused*), I also had to change the nodeBuilder code to match.
This is arguably harder to read. So it's possible that I should instead
keep the nodeBuilder version as `typeof f` and make an exception for
private name use.
* Emit namespace merge instead of object type
This makes the change smaller, overall.
* Fix isJSContainerFunctionDeclaration+namespace merges
Also improve emit style to match other namespace emit.
* Add isPrivate + test case from PR comments
Previously, intersections were only allowed as targets, but this was
just an artifact of the original implementation, which operated inside
the structural part of isRelatedTo. Removing this restriction catches
subtle bugs in React user code, where a function named `create` returns
a mapped type whose types are all branded numbers. The display of these
properties, for some original type `T`, is not `number & { __ }` but
the much-less-obvious `RegisteredStyle<T>`.
Previously, getWidenedTypedFromJSPropertyAssignment was not called for
Typescript code. Since property assignments on functions, it is. That
meant that property assignments would incorrectly create a JS container
for empty object literals in a property assignment, even in Typescript:
```ts
const one = () => 1
one.p = {}
one.p.q = {} // should not work in Typescript!
```
Now empty object literals never create expando objects in Typescript,
because getJSExpandoObjectType requires the declaration to be in a JS
file.
skipping narrowing if the old algorithm produces a type to which the
assigned type is not assignable.
This also means we'll no longer narrow for erroneous assignments where
the assigned type is not assignable to the declared type. This is the
reason for the numericLiteralTypes3 baseline change.
Fixes#26405.
Previously, they were mistakenly treated as private because of a check
that required all super property accesses (like `super.x()`) to be
references to a MethodDeclaration or MethodSignature. This change also
allows PrototypeProperty special assignment kinds.
* Allow special property assignments in TS
But only for functions and constant variable declarations initialised with
functions.
This specifically excludes class declarations and class expressions,
which differs from Javascript. That's because Typescript supports
`static` properties, which are equivalent to property assignments to a
class.
* Improve contextual typing predicate
Don't think it's right yet, but probably closer?
* More fixes.
The code is still fantastically ugly, but everything works the way it
should.
Also update baselines, even where it is ill-advised.
* Cleanup
* Remove extra whitespace
* Some kind of fix to isAnyDeclarationName
It's not done yet.
Specifically, in TS:
Special property assignments are supposed to be declaration sites (but not all
top-level assignments), and I think I
got them to be. (But not sure).
In JS:
Special property assignments are supposed to be declaration sites (but not all
top-level assignments), and I'm pretty sure ALL top-level assignments
have been declaration sites for some time. This is incorrect, and
probably means the predicate needs to be the same for both dialects.
* Add fourslash and improve isAnyDeclarationName
Now JS behaves the same as TS.
* Cleanup from PR comments
* This-property w/empty object init: use type annotation
* JS initializer type doesn't apply to this-property assignments
* Move getJSExpandoType into getWidenedType* functions
Plus some cleanup.
* Improved style from PR comments
* Parameters are not expando
* Classes can extend JS constructor functions
Now ES6 classes can extend ES5 constructor functions, although only
those written in a JS file.
Note that the static side assignability is checked. I need to write
tests to make sure that instance side assignability is checked too.
I haven't tested generic constructor functions yet either.
* Test static+instance assignability errors+generics
Note that generics do not work.
* Cleanup from PR comments
* Even more cleanup
* Update case of function name
* Fixes#26128 - signature comp for jsdoc @class.
Another issue caused by js functions tagged with jsdoc
`@constructor` not having construct signatures.
A jsdoc function type that constructs a type (`function(new: Ex)`),
has a construct signature and return value inferred as the
constructed type where as a jsdoc `@constructor` has no construct
signatures, and it's call signature has a void return type
(or undefined).
i.e:
```javascript
/** @constructor **/ function E() {};
// typeof E -> call signature: () => void
/** @param {function(new: E)} d */ function c(d) {}
// typeof d -> construct: () => E
```
--
This commit fixes this (in an inelegant way) by considering `@class` function signatures as construct signatures and synthesizing it's return value _only for signature comparison_.
There might be a slight performance hit, since the synthesized return value is not cached; but changing the `@class` function's return type in `getReturnTypeOfSignature` causes other issues.
* Update jsdoc function test to fix mistake.
* Allow type predicates
1. Parse type predicates. Note that they are parsed everywhere, and get
the appropriate error when used places besides a return type.
2. When creating a type predicate, correctly find the function's parameters
starting from the jsdoc return type.
* Fix type of TypePredicateNode.parent: add JSDocTypeExpression
* Update API baselines
* Handle JSDoc signature inside @type annotations
* Fix circularity when getting type predicates
Also move createTypePredicateFromTypePredicateNode closer to its use
* More cleanup based on review comments
typeMaybeAssignableTo.
typeMaybeAssignableTo decomposed unions at the top level of the assigned
type but didn't properly handle other unions that arose during
assignability checking, e.g., in the constraint of a generic lookup
type.
Fixes#26130.
* Fixes#26122.
When `resolveCall` does not resolve in `resolveNewExpression`, the error should only be thrown if there is a *defined* signature that is not-void.
* Fix other baselines to remove erroneous TS2350.
unmangled package name where appropriate.
Add a test case for an untyped sub-module of a scoped package with
typings. The other diagnostic message is covered by existing tests; I
guess no one looked at the baselines closely enough.
Fixes#23999.
* Properly infer `this` in tagged `@constructor`s.
`c.prototype.method = function() { this }` was already supported.
This commit add support to two more kinds relying on the JSDoc
`@constructor` tag. These are:
1. `/** @constructor */ function Example() { this }`
2. `/** @constructor */ var Example = function() { this }`
* Update the baseline for js constructorFunctions.
C3 and C4 `this` was set as `any`, now it is properly showing as
the class type.
* Fix lint errors
* Add circular initialisers to constructo fn tests.
* Error (`TS2348`) if calling tagged js constructors
When calling a JS function explicitly tagged with either `@class` or
`@constructor` the checker should throw a TS2348 not callable error.
* Don't resolve jsdoc classes with construct sigs.
This undoes the last commit that sought to change how js functions
tagged with `@class` were inferred. For some reason, currently
unknown, giving those functions construct signatures causes issues
in property assignment/member resolution (as seen in the
`typeFromPropertyAssignment12` test case).
Instead of changing the signature resolution, the error is explicitly
generated in `resolveCallExpression` for those functions.
* In JSDoc, resolve import types as values too
This is something that we probably should have been doing for some time.
Fixes#26049
* Fix whitespace lint
* Only bind module.exports if no local definition exists
Note that this uses `lookupSymbolForNameWorker`, which is really a
best-effort check since it only knows about symbols that it has already
encountered.
As a side-effect, even when `module` is bound as part of a
`module.exports` reference, it only declares it once instead of one
declaration per reference.
* Only type module.exports inside module files
It is an error inside script files, but the binder sometimes creates a
ModuleExports symbol because we doesn't know whether we have a commonjs
module until after binding is done.
* Only bind module.exports in a commonjs module
Note that this, too, is a best-effort check since evidence of
commonjs-ness may be found after a *reference* to module.exports. (A
reference to module.exports alone is not enough evidence that a file is
commonjs. It has to have an assignment to it.)
* Support the JSDoc @enum tag
`@enum` is used on a variable declaration with an object literal
initializer. It does a number of things:
1. The object literal has a closed set of properties, unlike other
object literals in Javascript.
2. The variable's name is resolvable as a type, but it just has the
declared type of the enum tag.
3. Each property's type must be assignable to the enum tag's declared type,
which can be any type.
For example,
```js
/** @enum {string} */
const Target = {
START: "START",
END: "END",
MISTAKE: 0, // error 'number' is not assignable to 'string' -- see (3)
}
Target.THIS_IS_AN_ERROR; // See (1)
/** @type {Target} See (2) */
var target = Target.START;
```
* Fix lint, add new test case, update API baselines
* Revert "Revert "Explicitly typed special assignments are context sensitive (#25619)""
This reverts commit 16676f2707.
* Revert "Revert "Explicitly typed prototype assignments are context sensitive (#25688)""
This reverts commit ff8c30d636.
* Initial, wasteful, solution
It burns a check flags. Probably necessary, but perhaps not.
I haven't accepted baselines, but they are a bit questionable. I'm not
sure the synthetic type is right, because I expected to see
{ "exports": typeof import("x") } but instead see { "x": typeof
import("x") }.
* Update some baselines
* module.exports= always uses lhs type
Conflicts between exports property assignments and exports assignments
should get a union type instead of an error.
* Fix lint and accept good user baselines
* Add tests based on user tests.
These currently fail.
* Fix all but 1 of user test bugs found by typing module.exports
Still quite messy and full of notes
* Follow merged symbols+allow any object type
This allows exports like `module.exports = new EE` to have properties
added to them.
Still messy, but I'm going to run user tests and look for regressions.
* Update improved user baselines
* Fix infinite recursion when checking module.exports
* Fix bogus use-before-def error
getExportSymbolOfValueSymbolIfExported should always merge its returned
symbol, whether it's symbol.exportSymbol or just symbol.
* Update user test baselines
* Cleanup
* More small cleanup
* Bind `module` of `module.exports` as a special symbol
Previously it was also special, but created during name resolution in
the checker. It made sense when there was only one special symbol for
all files, but now there is one `module` symbol per file.
* Fix parsing of parenthesized JSDoc parameters
Parenthesis can start a jsdoc function parameter since it is just a
type, and parenthesis can start a type:
```js
/** @type {function(((string))): void} */
```
However, this is not legal in other parameter lists:
```ts
function x((((a))): string) { }
```
This change makes jsdoc function parameter lists parse differently than
normal parameter lists by allowing parenthesis as a start character of
jsdoc parameters.
* Parse nested uses of jsdoc function types
* Fix test
* add grammar check for labeled function declaration
* fix debug failed on labeled class declaration
* move labeled statement check to binder and add more pattern for check
* update diagnostic message
* update baseline
* Explicitly typed prototype assignments:ctx sensitive
Follow up to #25619: Add the necessary code to type `prototype`
correctly in prototype assignments so that code like
`F.prototype = { ... }` properly makes the object literal context
sensitive.
* Fix lint