- Notifications
You must be signed in to change notification settings - Fork13.1k
Breaking Changes
These changes list where implementation differs between versions as the spec and compiler are simplified and inconsistencies are corrected.
For breaking changes to the compiler/services API, please check theAPI Breaking Changes page.
Promise.resolve now uses theAwaited type to unwrap Promise-like types passed to it.This means that it more often returns the rightPromise type, but that improved type can break existing code if it was expectingany orunknown instead of aPromise.For more information,see the original change.
When TypeScript first supported type-checking and compilation for JavaScript, it accidentally supported a feature called import elision.In short, if an import is not used as a value, or the compiler can detect that the import doesn't refer to a value at runtime, the compiler will drop the import during emit.
This behavior was questionable, especially the detection of whether the import doesn't refer to a value, since it means that TypeScript has to trust sometimes-inaccurate declaration files.In turn, TypeScript now preserves imports in JavaScript files.
// Input:import{someValue,SomeClass}from"some-module";/**@type {SomeType} */letval=someValue;// Previous Output:import{someValue}from"some-module";/**@type {SomeClass} */letval=someValue;// Current Output:import{someValue,SomeClass}from"some-module";/**@type {SomeType} */letval=someValue;
More information is available atthe implementing change.
Previously, TypeScript incorrectly prioritized thetypesVersions field over theexports field when resolving through apackage.json under--moduleResolution node16.If this change impacts your library, you may need to addtypes@ version selectors in yourpackage.json'sexports field.
{ "type": "module", "main": "./dist/main.js" "typesVersions": { "<4.8": { ".": ["4.8-types/main.d.ts"] }, "*": { ".": ["modern-types/main.d.ts"] } }, "exports": { ".": {+ "types@<4.8": "4.8-types/main.d.ts",+ "types": "modern-types/main.d.ts", "import": "./dist/main.js" } } }For more information,see this pull request.
Originally, the constraint of all type parameters in TypeScript was{} (the empty object type).Eventually the constraint was changed tounknown which also permitsnull andundefined.Outside ofstrictNullChecks, these types are interchangeable, but withinstrictNullChecks,unknown is not assignable to{}.
In TypeScript 4.8, understrictNullChecks, the type-checker disables a type safety hole that was maintained for backwards-compatibility, where type parameters were considered to always be assignable to{},object, and any other structured types with all-optional properties.
functionfoo<T>(x:T){consta:{}=x;// ~// Type 'T' is not assignable to type '{}'.constb:object=x;// ~// Type 'T' is not assignable to type 'object'.constc:{foo?:string,bar?:number}=x;// ~// Type 'T' is not assignable to type '{ foo?: string | undefined; bar?: number | undefined; }'.}
In such cases, you may need a type assertion onx, or a constraint of{} onT.
functionfoo<Textends{}>(x:T){// Worksconsta:{}=x;// Worksconstb:object=x;}
This behavior can come up in calls toObject.keys:
functionkeysEqual<T>(x:T,y:T){constxKeys=Object.keys(x);constyKeys=Object.keys(y);if(xKeys.length!==yKeys.length)returnfalse;for(leti=0;i<xKeys.length;i++){if(xKeys[i]!==yKeys[i])returnfalse;}returntrue;}
For the above, you might see an error message that looks like this:
Nooverloadmatchesthiscall.Overload1of2,'(o: {}): string[]',gavethefollowingerror.Argumentoftype'T'isnotassignabletoparameteroftype'{}'.Overload2of2,'(o: object): string[]',gavethefollowingerror.Argumentoftype'T'isnotassignabletoparameteroftype'object'.
Appropriately performing runtime checks to narrow the type, or using a type-assertion, may be the best way to deal with these new errors.
For more information, take a look atthe breaking PR here.
See Changes for Older Releases
When writing a...spread in JSX, TypeScript now enforces stricter checks that the given type is actually an object.As a results, values with the typesunknown andnever (and more rarely, just barenull andundefined) can no longer be spread into JSX elements.
So for the following example:
import*asReactfrom"react";interfaceProps{stuff?:string;}functionMyComponent(props:unknown){return<div{...props}/>;}
you'll now receive an error like the following:
Spread types may only be created from object types.This makes this behavior more consistent with spreads in object literals.
For more details,see the change on GitHub.
When asymbol value is used in a template string, it will trigger a runtime error in JavaScript.
letstr=`hello${Symbol()}`;// TypeError: Cannot convert a Symbol value to a string
As a result, TypeScript will issue an error as well;however, TypeScript now also checks if a generic value that is constrained to a symbol in some way is used in a template string.
functionlogKey<Sextendsstring|symbol>(key:S):S{// Now an error.console.log(`${key} is the key`);returnkey;}functionget<T,KextendskeyofT>(obj:T,key:K){// Now an error.console.log(`Grabbing property '${key}'.`);returnobj[key];}
TypeScript will now issue the following error:
Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.In some cases, you can get around this by wrapping the expression in a call toString, just like the error message suggests.
functionlogKey<Sextendsstring|symbol>(key:S):S{// Now an error.console.log(`${String(key)} is the key`);returnkey;}
In others, this error is too pedantic, and you might not ever care to even allowsymbol keys when usingkeyof.In such cases, you can switch tostring & keyof ...:
functionget<T,KextendskeyofT>(obj:T,key:K){// Now an error.console.log(`Grabbing property '${key}'.`);returnobj[key];}
For more information, you cansee the implementing pull request.
If you're creatingLanguageService instances, then providedLanguageServiceHosts will need to provide areadFile method.This change was necessary to support the newmoduleDetection compiler option.
You canread more on the change here.
Areadonly tuple will now treat itslength property asreadonly.This was almost never witnessable for fixed-length tuples, but was an oversight which could be observed for tuples with trailing optional and rest element types.
As a result, the following code will now fail:
functionoverwriteLength(tuple:readonly[string,string,string]){// Now errors.tuple.length=7;}
You canread more on this change here.
Object rest expressions now drop members that appear to be unspreadable on generic objects.In the following example...
classThing{someProperty=42;someMethod(){// ...}}functionfoo<TextendsThing>(x:T){let{ someProperty, ...rest}=x;// Used to work, is now an error!// Property 'someMethod' does not exist on type 'Omit<T, "someProperty" | "someMethod">'.rest.someMethod();}
the variablerest used to have the typeOmit<T, "someProperty"> because TypeScript would strictly analyze which other properties were destructured.This doesn't model how...rest would work in a destructuring from a non-generic type becausesomeMethod would typically be dropped as well.In TypeScript 4.6, the type ofrest isOmit<T, "someProperty" | "someMethod">.
This can also come up in cases when destructuring fromthis.When destructuringthis using a...rest element, unspreadable and non-public members are now dropped, which is consistent with destructuring instances of a class in other places.
classThing{someProperty=42;someMethod(){// ...}someOtherMethod(){let{ someProperty, ...rest}=this;// Used to work, is now an error!// Property 'someMethod' does not exist on type 'Omit<T, "someProperty" | "someMethod">'.rest.someMethod();}}
For more details,see the corresponding change here.
Previously, TypeScript would ignore most grammar errors in JavaScript apart from accidentally using TypeScript syntax in a JavaScript file.TypeScript now shows JavaScript syntax and binding errors in your file, such as using incorrect modifiers, duplicate declarations, and more.These will typically be most apparent in Visual Studio Code or Visual Studio, but can also occur when running JavaScript code through the TypeScript compiler.
You can explicitly turn these errors off by inserting a// @ts-nocheck comment at the top of your file.
For more information, see thefirst andsecond implementing pull requests for these features.
TypeScript 4.5 contains changes to its built-in declaration files which may affect your compilation;however,these changes were fairly minimal, and we expect most code will be unaffected.
BecauseAwaited is now used inlib.d.ts and as a result ofawait, you may see certain generic types change that might cause incompatibilities.This may cause issues when providing explicit type arguments to functions likePromise.all,Promise.allSettled, etc.
Often, you can make a fix by removing type arguments altogether.
- Promise.all<boolean, boolean>(...)+ Promise.all(...)
More involved cases will require you to replace a list of type arguments with a single type argument of a tuple-like type.
- Promise.all<boolean, boolean>(...)+ Promise.all<[boolean, boolean]>(...)
However, there will be occasions when a fix will be a little bit more involved, and replacing the types with a tuple of the original type arguments won't be enough.One example where this occasionally comes up is when an element is possibly aPromise or non-Promise.In those cases, it's no longer okay to unwrap the underlying element type.
- Promise.all<boolean | undefined, boolean | undefined>(...)+ Promise.all<[Promise<boolean> | undefined, Promise<boolean> | undefined]>(...)
Template strings in TypeScript previously just used the+ operator when targeting ES3 or ES5;however, this leads to some divergences between the use of.valueOf() and.toString() which ends up being less spec-compliant.This is usually not noticeable, but is particularly important when using upcoming standard library additions likeTemporal.
TypeScript now uses calls to.concat() onstrings.This gives code the same behavior regardless of whether it targets ES3 and ES5, or ES2015 and later.Most code should be unaffected, but you might now see different results on values that define separatevalueOf() andtoString() methods.
importmoment= require("moment");// Before: "Moment: Wed Nov 17 2021 16:23:57 GMT-0800"// After: "Moment: 1637195037348"console.log(`Moment:${moment()}`);
More more information,see the original issue.
It's an easy mistake to accidentally forget about thecompilerOptions section in atsconfig.json.To help catch this mistake, in TypeScript 4.5, it is an error to add a top-level field which matches any of the available options incompilerOptionswithout having also definedcompilerOptions in thattsconfig.json.
TypeScript no longer allows types to be assignable to conditional types that useinfer, or that are distributive.Doing so previously often ended up causing major performance issues.For more information,see the specific change on GitHub.
As with every TypeScript version, declarations forlib.d.ts (especially the declarations generated for web contexts), have changed.You can consultour list of knownlib.dom.d.ts changes to understand what is impacted.
In earlier versions of TypeScript, calling an import from CommonJS, AMD, and other non-ES module systems would set thethis value of the called function.Specifically, in the following example, when callingfooModule.foo(), thefoo() method will havefooModule set as the value ofthis.
// Imagine this is our imported module, and it has an export named 'foo'.letfooModule={foo(){console.log(this);}};fooModule.foo();
This is not the way exported functions in ECMAScript are supposed to work when we call them.That's why TypeScript 4.4 intentionally discards thethis value when calling imported functions, by using the following emit.
// Imagine this is our imported module, and it has an export named 'foo'.letfooModule={foo(){console.log(this);}};// Notice we're actually calling '(0, fooModule.foo)' now, which is subtly different.(0,fooModule.foo)();
For more information, you can read up morehere.
Users running with the--strict flag may see new errors aroundcatch variables beingunknown due to the new--useUnknownForCatchVariables flag, especially if the existing code assumes onlyError values have been caught.This often results in error messages such as:
Property 'message' does not exist on type 'unknown'.Property 'name' does not exist on type 'unknown'.Property 'stack' does not exist on type 'unknown'.Object is of type 'unknown'.To get around this, you can specifically add runtime checks to ensure that the thrown type matches your expected type.Otherwise, you can just use a type assertion, add an explicit: any to your catch variable, or turn off--useUnknownInCatchVariables.
In prior versions, TypeScript introduced "Always Truthy Promise checks" to catch code where anawait may have been forgotten;however, the checks only applied to named declarations.That meant that while this code would correctly receive an error...
asyncfunctionfoo():Promise<boolean>{returnfalse;}asyncfunctionbar():Promise<string>{constfooResult=foo();if(fooResult){// <- error! :Dreturn"true";}return"false";}
...the following code would not.
asyncfunctionfoo():Promise<boolean>{returnfalse;}asyncfunctionbar():Promise<string>{if(foo()){// <- no error :(return"true";}return"false";}
TypeScript 4.4 now flags both.For more information,read up on the original change.
The following code is now an error because abstract properties may not have initializers:
abstractclassC{abstractprop=1;// ~~~~// Property 'prop' cannot have an initializer because it is marked abstract.}
Instead, you may only specify a type for the property:
abstractclassC{abstractprop:number;}
Certainenums are consideredunionenums when their members are either automatically filled in, or trivially written.In those cases, an enum can recall each value that it potentially represents.
In TypeScript 4.3, if a value with a unionenum type is compared with a numeric literal that it could never be equal to, then the type-checker will isue an error.
enumE{A=0,B=1,}functiondoSomething(x:E){// Error! This condition will always return 'false' since the types 'E' and '-1' have no overlap.if(x===-1){// ...}}
As a workaround, you can re-write an annotation to include the appropriate literal type.
enumE{A=0,B=1,}// Include -1 in the type, if we're really certain that -1 can come through.functiondoSomething(x:E|-1){if(x===-1){// ...}}
You can also use a type-assertion on the value.
enumE{A=0,B=1,}functiondoSomething(x:E){// Use a type asertion on 'x' because we know we're not actually just dealing with values from 'E'.if((xasnumber)===-1){// ...}}
Alternatively, you can re-declare your enum to have a non-trivial initializer so that any number is both assignable and comparable to that enum. This may be useful if the intent is for the enum to specify a few well-known values.
enumE{// the leading + on 0 opts TypeScript out of inferring a union enum.A=+0,B=1,}
For more details,see the original change
When ayield expression is captured, but isn't contextually typed (i.e. TypeScript can't figure out what the type is), TypeScript will now issue an implicitany error.
function*g1(){constvalue=yield1;// report implicit any error}function*g2(){yield1;// result is unused, no error}function*g3(){constvalue:string=yield1;// result is contextually typed by type annotation of `value`, no error.}function*g3():Generator<number,void,string>{constvalue=yield1;// result is contextually typed by return-type annotation of `g3`, no error.}
See more details inthe corresponding changes.
Type arguments were already not allowed in JavaScript, but in TypeScript 4.2, the parser will parse them in a more spec-compliant way.So when writing the following code in a JavaScript file:
f<T>(100)
TypeScript will parse it as the following #"(f < T) > (100)">
(f<T)>(100)
This may impact you if you were leveraging TypeScript's API to parse type constructs in JavaScript files, which may have occurred when trying to parse Flow files.
In JavaScript, it is a runtime error to use a non-object type on the right side of thein operator.TypeScript 4.2 ensures this can be caught at design-time.
"foo"in42// ~~// error! The right-hand side of an 'in' expression must not be a primitive.
This check is fairly conservative for the most part, so if you have received an error about this, it is likely an issue in the code.
Members marked asabstract can no longer be marked asasync.The fix here is to remove theasync keyword, since callers are only concerned with the return type.
When writing code like the following
newPromise(resolve=>{doSomethingAsync(()=>{doSomething();resolve();})})
You may get an error like the following:
resolve() ~~~~~~~~~error TS2554: Expected 1 arguments, but got 0. An argument for 'value' was not provided.This is becauseresolve no longer has an optional parameter, so by default, it must now be passed a value.Often this catches legitimate bugs with usingPromises.The typical fix is to pass it the correct argument, and sometimes to add an explicit type argument.
newPromise<number>(resolve=>{// ^^^^^^^^doSomethingAsync(value=>{doSomething();resolve(value);// ^^^^^})})
However, sometimesresolve() really does need to be called without an argument.In these cases, we can givePromise an explicitvoid generic type argument (i.e. write it out asPromise<void>).This leverages new functionality in TypeScript 4.1 where a potentially-void trailing parameter can become optional.
newPromise<void>(resolve=>{// ^^^^^^doSomethingAsync(()=>{doSomething();resolve();})})
TypeScript 4.1 ships with a quick fix to help fix this break.
Note: This change, and the description of the previous behavior, apply only under--strictNullChecks.
Previously, when anany orunknown appeared on the left-hand side of an&&, it was assumed to be definitely truthy, which made the type of the expression the type of the right-hand side:
// Before:functionbefore(x:any,y:unknown){constdefinitelyThree=x&&3;// 3constdefinitelyFour=y&&4;// 4}// Passing any falsy values here demonstrates that `definitelyThree` and `definitelyFour`// are not, in fact, definitely 3 and 4 at runtime.before(false,0);
In TypeScript 4.1, under--strictNullChecks, whenany orunknown appears on the left-hand side of an&&, the type of the expression isany orunknown, respectively:
// After:functionafter(x:any,y:unknown){constmaybeThree=x&&3;// anyconstmaybeFour=y&&4;// unknown}
This change introduces new errors most frequently where TypeScript previously failed to notice that anunknown in an&& expression may not produce aboolean:
functionisThing(x:unknown):boolean{returnx&&typeofx==="object"&&x.hasOwnProperty("thing");// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// error!// Type 'unknown' is not assignable to type 'boolean'.}
Ifx is a falsy value other thanfalse, the function will return it, in conflict with theboolean return type annotation. The error can be resolved by replacing the firstx in the return expression with!!x.
See more details on theimplementing pull request.
In JavaScript, object spreads (like{ ...foo }) don't operate over falsy values.So in code like{ ...foo },foo will be skipped over if it'snull orundefined.
Many users take advantage of this to spread in properties "conditionally".
interfacePerson{name:string;age:number;location:string;}interfaceAnimal{name:string;owner:Person;}functioncopyOwner(pet?:Animal){return{ ...(pet&&pet.owner),otherStuff:123}}// We could also use optional chaining here:functioncopyOwner(pet?:Animal){return{ ...(pet?.owner),otherStuff:123}}
Here, ifpet is defined, the properties ofpet.owner will be spread in - otherwise, no properties will be spread into the returned object.
The return type ofcopyOwner was previously a union type based on each spread:
{ x: number } | { x: number, name: string, age: number, location: string }This modeled exactly how the operation would occur: ifpet was defined, all the properties fromPerson would be present; otherwise, none of them would be defined on the result.It was an all-or-nothing operation.
However, we've seen this pattern taken to the extreme, with hundreds of spreads in a single object, each spread potentially adding in hundreds or thousands of properties.It turns out that for various reasons, this ends up being extremely expensive, and usually for not much benefit.
In TypeScript 4.1, the returned type instead uses all-optional properties.
{ x: number; name?: string; age?: number; location?: string;}This ends up performing better and generally displaying better too.
For more details,see the original change.
TypeScript would previously relate parameters that didn't correspond to each other by relating them to the typeany.Withchanges in TypeScript 4.1, the language now skips this process entirely.This means that some cases of assignability will now fail, but it also means that some cases of overload resolution can fail as well.For example, the overloads ofutil.promisify in Node.js may select a different overload in TypeScript 4.1, sometimes causing different errors downstream.
As a workaround, you may be best using a type assertion to squelch errors.
Previously, it was only an error for properties to override accessors, or accessors to override properties, when usinguseDefineForClassFields; however, TypeScript now always issues an error when declaring a property in a derived class that would override a getter or setter in the base class.
classBase{getfoo(){return100;}setfoo(){// ...}}classDerivedextendsBase{foo=10;// ~~~// error!// 'foo' is defined as an accessor in class 'Base',// but is overridden here in 'Derived' as an instance property.}
classBase{prop=10;}classDerivedextendsBase{getprop(){// ~~~~// error!// 'prop' is defined as a property in class 'Base', but is overridden here in 'Derived' as an accessor.return100;}}
When using thedelete operator instrictNullChecks, the operand must now beany,unknown,never, or be optional (in that it containsundefined in the type).Otherwise, use of thedelete operator is an error.
interfaceThing{prop:string;}functionf(x:Thing){deletex.prop;// ~~~~~~// error! The operand of a 'delete' operator must be optional.}
See more details onthe implementing pull request.
See more details onthe implementing pull request.
TypeScript recently implemented the optional chaining operator, but we've received user feedback that the behavior of optional chaining (?.) with the non-null assertion operator (!) is extremely counter-intuitive.
Specifically, in previous versions, the code
foo?.bar!.baz
was interpreted to be equivalent to the following JavaScript.
(foo?.bar).baz
In the above code the parentheses stop the "short-circuiting" behavior of optional chaining, so iffoo isundefined, accessingbaz will cause a runtime error.
The Babel team who pointed this behavior out, and most users who provided feedback to us, believe that this behavior is wrong.We do too!The thing we heard the most was that the! operator should just "disappear" since the intent was to removenull andundefined from the type ofbar.
In other words, most people felt that the original snippet should be interpreted as
foo?.bar.baz
which just evaluates toundefined whenfoo isundefined.
This is a breaking change, but we believe most code was written with the new interpretation in mind.Users who want to revert to the old behavior can add explicit parentheses around the left side of the! operator.
(foo?.bar)!.baz
For more information,see the corresponding pull request.
The JSX Specification forbids the use of the} and> characters in text positions.TypeScript and Babel have both decided to enforce this rule to be more comformant.The new way to insert these characters is to use an HTML escape code (e.g.<span> 2 > 1 </div>) or insert an expression with a string literal (e.g.<span> 2 {">"} 1 </div>).
In the presence of code like this, you'll get an error message along the lines of
Unexpected token. Did you mean `{'>'}` or `>`?Unexpected token. Did you mean `{'}'}` or `}`?For example:
letdirections=<span>Navigate to: Menu Bar>Tools>Options</div>// ~ ~// Unexpected token. Did you mean `{'>'}` or `>`?
For more information, see the correspondingpull request.
Generally, an intersection type likeA & B is assignable toC if eitherA orB is assignable toC; however, sometimes that has problems with optional properties.For example, take the following:
interfaceA{a:number;// notice this is 'number'}interfaceB{b:string;}interfaceC{a?:boolean;// notice this is 'boolean'b:string;}declareletx:A&B;declarelety:C;y=x;
In previous versions of TypeScript, this was allowed because whileA was totally incompatible withC,Bwas compatible withC.
In TypeScript 3.9, so long as every type in an intersection is a concrete object type, the type system will consider all of the properties at once.As a result, TypeScript will see that thea property ofA & B is incompatible with that ofC:
Type 'A & B' is not assignable to type 'C'. Types of property 'a' are incompatible. Type 'number' is not assignable to type 'boolean | undefined'.For more information on this change,see the corresponding pull request.
There are a few cases where you might end up with types that describe values that just don't exist.For example
declarefunctionsmushObjects<T,U>(x:T,y:U):T&U;interfaceCircle{kind:"circle";radius:number;}interfaceSquare{kind:"square";sideLength:number;}declareletx:Circle;declarelety:Square;letz=smushObjects(x,y);console.log(z.kind);
This code is slightly weird because there's really no way to create an intersection of aCircle and aSquare - they have two incompatiblekind fields.In previous versions of TypeScript, this code was allowed and the type ofkind itself wasnever because"circle" & "square" described a set of values that couldnever exist.
In TypeScript 3.9, the type system is more aggressive here - it notices that it's impossible to intersectCircle andSquare because of theirkind properties.So instead of collapsing the type ofz.kind tonever, it collapses the type ofz itself (Circle & Square) tonever.That means the above code now errors with:
Property 'kind' does not exist on type 'never'.Most of the breaks we observed seem to correspond with slightly incorrect type declarations.For more details,see the original pull request.
In older versions of TypeScript,get andset accessors in classes were emitted in a way that made them enumerable; however, this wasn't compliant with the ECMAScript specification which states that they must be non-enumerable.As a result, TypeScript code that targeted ES5 and ES2015 could differ in behavior.
Withrecent changes, TypeScript 3.9 now conforms more closely with ECMAScript in this regard.
In previous versions of TypeScript, a type parameter constrained toany could be treated asany.
functionfoo<Textendsany>(arg:T){arg.spfjgerijghoied;// no error!}
This was an oversight, so TypeScript 3.9 takes a more conservative approach and issues an error on these questionable operations.
functionfoo<Textendsany>(arg:T){arg.spfjgerijghoied;// ~~~~~~~~~~~~~~~// Property 'spfjgerijghoied' does not exist on type 'T'.}
Seethe original pull request for more details.
In previous TypeScript versions, declarations likeexport * from "foo" would be dropped in our JavaScript output iffoo didn't export any values.This sort of emit is problematic because it's type-directed and can't be emulated by Babel.TypeScript 3.9 will always emit theseexport * declarations.In practice, we don't expect this to break much existing code, but bundlers may have a harder time tree-shaking the code.
You can see the specific changes inthe original pull request.
When targeting module systems like CommonJS in ES5 and above, TypeScript will use get accessors to emulate live bindings so that changes to a variable in one module are witnessed in any exporting modules. This change is meant to make TypeScript's emit more compliant with ECMAScript modules.
For more details, seethe PR that applies this change.
TypeScript now hoists exported declarations to the top of the file when targeting module systems like CommonJS in ES5 and above. This change is meant to make TypeScript's emit more compliant with ECMAScript modules. For example, code like
export*from"mod";exportconstnameFromMod=0;
previously had output like
__exportStar(exports,require("mod"));exports.nameFromMod=0;
However, because exports now useget-accessors, this assignment would throw because__exportStar now makes get-accesors which can't be overridden with a simple assignment. Instead, TypeScript 3.9 emits the following:
exports.nameFromMod=void0;__exportStar(exports,require("mod"));exports.nameFromMod=0;
Seethe original pull request for more information.
Previously, excess properties were unchecked when assigning to unions whereany type had an index signature - even if that excess property couldnever satisfy that index signature.In TypeScript 3.8, the type-checker is stricter, and only "exempts" properties from excess property checks if that property could plausibly satisfy an index signature.
constobj1:{[x:string]:number}|{a:number};obj1={a:5,c:'abc'}// ~// Error!// The type '{ [x: string]: number }' no longer exempts 'c'// from excess property checks on '{ a: number }'.letobj2:{[x:string]:number}|{[x:number]:number};obj2={a:'abc'};// ~// Error!// The types '{ [x: string]: number }' and '{ [x: number]: number }' no longer exempts 'a'// from excess property checks against '{ [x: number]: number }',// and it *is* sort of an excess property because 'a' isn't a numeric property name.// This one is more subtle.
In the following code,param is now marked with an error undernoImplicitAny.
functionfoo(f:()=>void){// ...}foo((param?)=>{// ...});
This is because there is no corresponding parameter for the type off infoo.This seems unlikely to be intentional, but it can be worked around by providing an explicit type forparam.
Historically, TypeScript's support for checking JavaScript has been lax in certain ways in order to provide an approachable experience.
For example, users often usedObject in JSDoc to mean, "some object, I dunno what", we've treated it asany.
//@ts-check/** *@param thing {Object} some object, i dunno what */functiondoSomething(thing){letx=thing.x;lety=thing.y;thing();}
This is because treating it as TypeScript'sObject type would end up in code reporting uninteresting errors, since theObject type is an extremely vague type with few capabilities other than methods liketoString andvalueOf.
However, TypeScriptdoes have a more useful type namedobject (notice that lowercaseo).Theobject type is more restrictive thanObject, in that it rejects all primitive types likestring,boolean, andnumber.Unfortunately, bothObject andobject were treated asany in JSDoc.
Becauseobject can come in handy and is used significantly less thanObject in JSDoc, we've removed the special-case behavior in JavaScript files when usingnoImplicitAny so that in JSDoc, theobject type really refers to the non-primitiveobject type.
As per the ECMAScript specification, class declarations with methods namedconstructor are now constructor functions, regardless of whether they are declared using identifier names, or string names.
classC{"constructor"(){console.log("I am the constructor now.");}}
A notable exception, and the workaround to this break, is using a computed property whose name evaluates to"constructor".
classD{["constructor"](){console.log("I'm not a constructor - just a plain method!");}}
Many declarations have been removed or changed withinlib.dom.d.ts.This includes (but isn't limited to) the following:
- The global
windowis no longer defined as typeWindow- instead, it is defined as typeWindow & typeof globalThis. In some cases, it may be better to refer to its type astypeof window. GlobalFetchis gone. Instead, useWindowOrWorkerGlobalScope- Certain non-standard properties on
Navigatorare gone. - The
experimental-webglcontext is gone. Instead, usewebglorwebgl2.
In JavaScript files, TypeScript will only consult immediately preceding JSDoc comments to figure out declared types.
/** *@param {string} arg *//** * oh, hi, were you trying to type something? */functionwhoWritesFunctionsLikeThis(arg){// 'arg' has type 'any'}
Previously keywords were not allowed to contain escape sequences.TypeScript 3.6 disallows them.
while(true){\u0063ontinue;// ~~~~~~~~~~~~~// error! Keywords cannot contain escape characters.}
In TypeScript 3.5,generic type parameters without an explicit constraint are now implicitly constrained tounknown, whereas previously the implicit constraint of type parameters was the empty object type{}.
In practice,{} andunknown are pretty similar, but there are a few key differences:
{}can be indexed with a string (k["foo"]), though this is an implicitanyerror under--noImplicitAny.{}is assumed to not benullorundefined, whereasunknownis possibly one of those values.{}is assignable toobject, butunknownis not.
On the caller side, this typically means that assignment toobject will fail, and methods onObject liketoString,toLocaleString,valueOf,hasOwnProperty,isPrototypeOf, andpropertyIsEnumerable will no longer be available.
functionfoo<T>(x:T):[T,string]{return[x,x.toString()]// ~~~~~~~~ error! Property 'toString' does not exist on type 'T'.}
As a workaround, you can add an explicit constraint of{} to a type parameter to get the old behavior.
// vvvvvvvvvvfunctionfoo<Textends{}>(x:T):[T,string]{return[x,x.toString()]}
From the caller side, failed inferences for generic type arguments will result inunknown instead of{}.
functionparse<T>(x:string):T{returnJSON.parse(x);}// k has type 'unknown' - previously, it was '{}'.constk=parse("...");
As a workaround, you can provide an explicit type argument:
// 'k' now has type '{}'constk=parse<{}>("...");
The index signature{ [s: string]: any } in TypeScript behaves specially: it's a valid assignment target for any object type.This is a special rule, since types with index signatures don't normally produce this behavior.
Since its introduction, the typeunknown in an index signature behaved the same way:
letdict:{[s:string]:unknown};// Was OKdict=()=>{};
In general this rule makes sense; the implied constraint of "all its properties are some subtype ofunknown" is trivially true of any object type.However, in TypeScript 3.5, this special rule is removed for{ [s: string]: unknown }.
This was a necessary change because of the change from{} tounknown when generic inference has no candidates.Consider this code:
declarefunctionsomeFunc():void;declarefunctionfn<T>(arg:{[k:string]:T}):void;fn(someFunc);
In TypeScript 3.4, the following sequence occurred:
- No candidates were found for
T Tis selected to be{}someFuncisn't assignable toargbecause there are no special rules allowing arbitrary assignment to{ [k: string]: {} }- The call is correctly rejected
Due to changes around unconstrained type parameters falling back tounknown (see above),arg would have had the type{ [k: string]: unknown }, which anything is assignable to, so the call would have incorrectly been allowed.That's why TypeScript 3.5 removes the specialized assignability rule to permit assignment to{ [k: string]: unknown }.
Note that fresh object literals are still exempt from this check.
constobj={m:10};// OKconstdict:{[s:string]:unknown}=obj;
Depending on the intended behavior of{ [s: string]: unknown }, several alternatives are available:
{ [s: string]: any }{ [s: string]: {} }objectunknownany
We recommend sketching out your desired use cases and seeing which one is the best option for your particular use case.
TypeScript has a feature calledexcess property checking in object literals.This feature is meant to detect typos for when a type isn't expecting a specific property.
typeStyle={alignment:string,color?:string};consts:Style={alignment:"center",colour:"grey"// ^^^^^^ error!};
In TypeScript 3.4 and earlier, certain excess properties were allowed in situations where they really shouldn't have been.
Consider this code:
typePoint={x:number;y:number;};typeLabel={name:string;};constpl:Point|Label={x:0,y:0,name:true// <- danger!};
Excess property checking was previously only capable of detecting properties which weren't present inany member of a target union type.
In TypeScript 3.5, these excess properties are now correctly detected, and the sample above correctly issues an error.
Note that it's still legal to be assignable to multiple parts of a union:
constpl:Point|Label={x:0,y:0,name:"origin"// OK};
We have not witnessed examples where this checking hasn't caught legitimate issues, but in a pinch, any of the workarounds to disable excess property checking will apply:
- Add a type assertion onto the object (e.g.
{ myProp: SomeType } as ExpectedType) - Add an index signature to the expected type to signal that unspecified properties are expected (e.g.
interface ExpectedType { myProp: SomeType; [prop: string]: unknown })
TypeScript allows you to represent the abstract operation of accessing a property of an object via the name of that property:
typeA={s:string;n:number;};functionread<KextendskeyofA>(arg:A,key:K):A[K]{returnarg[key];}consta:A={s:"",n:0};constx=read(a,"s");// x: string
While commonly used for reading values from an object, you can also use this for writes:
functionwrite<KextendskeyofA>(arg:A,key:K,value:A[K]):void{arg[key]=value;}
In TypeScript 3.4, the logic used to validate awrite was much too permissive:
functionwrite<KextendskeyofA>(arg:A,key:K,value:A[K]):void{// ???arg[key]="hello, world";}// Breaks the object by putting a string where a number should bewrite(a,"n");
In TypeScript 3.5, this logic is fixed and the above sample correctly issues an error.
Most instances of this error represent potential errors in the relevant code.
One example we found looked like this:
typeT={a:string,x:number,y:number};functionwrite<KextendskeyofT>(obj:T,k:K){// Trouble waitingobj[k]=1;}constsomeObj:T={a:"",x:0,y:0};// Note: write(someObj, "a") never occurs, so the code is technically bug-free (?)write(someObj,"x");write(someObj,"y");
This function can be fixed to only accept keys which map to numeric properties:
// Generic helper type that produces the keys of an object// type which map to properties of some other specific typetypeKeysOfType<TObj,TProp,KextendskeyofTObj=keyofTObj>=KextendsK ?TObj[K]extendsTProp ?K :never :never;functionwrite(obj:SomeObj,k:KeysOfType<SomeObj,number>){// OKobj[k]=1;}constsomeObj:SomeObj={a:"",x:0,y:0};write(someObj,"x");write(someObj,"y");// Correctly an errorwrite(someObj,"a");
TypeScript 3.5 includes a newOmit helper type.As a result, any global declarations ofOmit included in your project will result in the following error message:
Duplicateidentifier'Omit'.
Two workarounds may be used here:
- Delete the duplicate declaration and use the one provided in
lib.d.ts. - Export the existing declaration from a module file or a namespace to avoid a global collision. Existing usages can use an
importor explicit reference to your project's oldOmittype.
In ECMAScript 5 environments,Object.keys throws an exception if passed any non-object argument:
// Throws if run in an ES5 runtimeObject.keys(10);
In ECMAScript 2015,Object.keys returns[] if its argument is a primitive:
// [] in ES6 runtimeObject.keys(10);
This is a potential source of error that wasn't previously identified.
In TypeScript 3.5, iftarget (or equivalentlylib) isES5, calls toObject.keys must pass a validobject.
In general, errors here represent possible exceptions in your application and should be treated as such.If you happen to know through other means that a value is anobject, a type assertion is appropriate:
functionfn(arg:object|number,isArgActuallyObject:boolean){if(isArgActuallyObject){constk=Object.keys(argasobject);}}
Note that this change interacts with the change in generic inference from{} tounknown, because{} is a validobject whereasunknown isn't:
declarefunctionfn<T>():T;// Was OK in TypeScript 3.4, errors in 3.5 under --target ES5Object.keys(fn());
The type of top-levelthis is now typed astypeof globalThis instead ofany.As a consequence, you may receive errors for accessing unknown values onthis undernoImplicitAny.
// previously okay in noImplicitAny, now an errorthis.whargarbl=10;
Note that code compiled undernoImplicitThis will not experience any changes here.
In certain cases, TypeScript 3.4's improved inference might produce functions that are generic, rather than ones that take and return their constraints (usually{}).
declarefunctioncompose<T,U,V>(f:(arg:T)=>U,g:(arg:U)=>V):(arg:T)=>V;functionlist<T>(x:T){return[x];}functionbox<T>(value:T){return{ value};}letf=compose(list,box);letx=f(100)// In TypeScript 3.4, 'x.value' has the type//// number[]//// but it previously had the type//// {}[]//// So it's now an error to push in a string.x.value.push("hello");
An explicit type annotation onx can get rid of the error.
TypeScript now uses types that flow into function calls (likethen in the below example) to contextually type function arguments (like the arrow function in the below example).
functionisEven(prom:Promise<number>):Promise<{success:boolean}>{returnprom.then((x)=>{returnx%2===0 ?{success:true} :Promise.resolve({success:false});});}
This is generally an improvement, but in the above example it causestrue andfalse to acquire literal types which is undesirable.
Argument of type '(x: number) => Promise<{ success: false; }> | { success: true; }' is not assignable to parameter of type '(value: number) => { success: false; } | PromiseLike<{ success: false; }>'. Type 'Promise<{ success: false; }> | { success: true; }' is not assignable to type '{ success: false; } | PromiseLike<{ success: false; }>'. Type '{ success: true; }' is not assignable to type '{ success: false; } | PromiseLike<{ success: false; }>'. Type '{ success: true; }' is not assignable to type '{ success: false; }'. Types of property 'success' are incompatible.The appropriate workaround is to add type arguments to the appropriate call - thethen method call in this example.
functionisEven(prom:Promise<number>):Promise<{success:boolean}>{// vvvvvvvvvvvvvvvvvvreturnprom.then<{success:boolean}>((x)=>{returnx%2===0 ?{success:true} :Promise.resolve({success:false});});}
In TypeScript 3.3 with--strictFunctionTypes off, generic types declared withinterface were assumed to always be covariant with respect to their type parameter.For function types, this behavior was generally not observable.However, for genericinterface types that used their type parameters withkeyof positions - a contravariant use - these types behaved incorrectly.
In TypeScript 3.4, variance of types declared withinterface is now correctly measured in all cases.This causes an observable breaking change for interfaces that used a type parameter only inkeyof (including places likeRecord<K, T> which is an alias for a type involvingkeyof K). The example above is one such possible break.
interfaceHasX{x:any}interfaceHasY{y:any}declareconstsource:HasX|HasY;declareconstproperties:KeyContainer<HasX>;interfaceKeyContainer<T>{key:keyofT;}functionreadKey<T>(source:T,prop:KeyContainer<T>){console.log(source[prop.key])}// This call should have been rejected, because we might// incorrectly be reading 'x' from 'HasY'. It now appropriately errors.readKey(source,properties);
This error is likely indicative of an issue with the original code.
wheelDeltaX,wheelDelta, andwheelDeltaZ have all been removed as they is a deprecated properties onWheelEvents.
Solution: UsedeltaX,deltaY, anddeltaZ instead.
Certain parameters no longer acceptnull, or now accept more specific types as per the corresponding specifications that describe the DOM.
TypeScript's built-in.d.ts library (lib.d.ts and family) is now partially generated from Web IDL files from the DOM specification. As a result some vendor-specific types have been removed.
Click here to read the full list of removed types:
CanvasRenderingContext2D.mozImageSmoothingEnabledCanvasRenderingContext2D.msFillRuleCanvasRenderingContext2D.oImageSmoothingEnabledCanvasRenderingContext2D.webkitImageSmoothingEnabledDocument.caretRangeFromPointDocument.createExpressionDocument.createNSResolverDocument.execCommandShowHelpDocument.exitFullscreenDocument.exitPointerLockDocument.focusDocument.fullscreenElementDocument.fullscreenEnabledDocument.getSelectionDocument.msCapsLockWarningOffDocument.msCSSOMElementFloatMetricsDocument.msElementsFromRectDocument.msElementsFromPointDocument.onvisibilitychangeDocument.onwebkitfullscreenchangeDocument.onwebkitfullscreenerrorDocument.pointerLockElementDocument.queryCommandIndetermDocument.URLUnencodedDocument.webkitCurrentFullScreenElementDocument.webkitFullscreenElementDocument.webkitFullscreenEnabledDocument.webkitIsFullScreenDocument.xmlEncodingDocument.xmlStandaloneDocument.xmlVersionDocumentType.entitiesDocumentType.internalSubsetDocumentType.notationsDOML2DeprecatedSizePropertyElement.msContentZoomFactorElement.msGetUntransformedBoundsElement.msMatchesSelectorElement.msRegionOverflowElement.msReleasePointerCaptureElement.msSetPointerCaptureElement.msZoomToElement.onwebkitfullscreenchangeElement.onwebkitfullscreenerrorElement.webkitRequestFullScreenElement.webkitRequestFullscreenElementCSSInlineStyleExtendableEventInitExtendableMessageEventInitFetchEventInitGenerateAssertionCallbackHTMLAnchorElement.MethodsHTMLAnchorElement.mimeTypeHTMLAnchorElement.namePropHTMLAnchorElement.protocolLongHTMLAnchorElement.urnHTMLAreasCollectionHTMLHeadElement.profileHTMLImageElement.msGetAsCastingSourceHTMLImageElement.msGetAsCastingSourceHTMLImageElement.msKeySystemHTMLImageElement.msPlayToDisabledHTMLImageElement.msPlayToDisabledHTMLImageElement.msPlayToPreferredSourceUriHTMLImageElement.msPlayToPreferredSourceUriHTMLImageElement.msPlayToPrimaryHTMLImageElement.msPlayToPrimaryHTMLImageElement.msPlayToSourceHTMLImageElement.msPlayToSourceHTMLImageElement.xHTMLImageElement.yHTMLInputElement.webkitdirectoryHTMLLinkElement.importHTMLMetaElement.charsetHTMLMetaElement.urlHTMLSourceElement.msKeySystemHTMLStyleElement.disabledHTMLSummaryElementMediaQueryListListenerMSAccountInfoMSAudioLocalClientEventMSAudioLocalClientEventMSAudioRecvPayloadMSAudioRecvSignalMSAudioSendPayloadMSAudioSendSignalMSConnectivityMSCredentialFilterMSCredentialParametersMSCredentialsMSCredentialSpecMSDCCEventMSDCCEventInitMSDelayMSDescriptionMSDSHEventMSDSHEventInitMSFIDOCredentialParametersMSIceAddrTypeMSIceTypeMSIceWarningFlagsMSInboundPayloadMSIPAddressInfoMSJitterMSLocalClientEventMSLocalClientEventBaseMSNetworkMSNetworkConnectivityInfoMSNetworkInterfaceTypeMSOutboundNetworkMSOutboundPayloadMSPacketLossMSPayloadBaseMSPortRangeMSRelayAddressMSSignatureParametersMSStatsTypeMSStreamReaderMSTransportDiagnosticsStatsMSUtilizationMSVideoPayloadMSVideoRecvPayloadMSVideoResolutionDistributionMSVideoSendPayloadNotificationEventInitPushEventInitPushSubscriptionChangeInitRTCIdentityAssertionResultRTCIdentityProviderRTCIdentityProviderDetailsRTCIdentityValidationResultScreen.deviceXDPIScreen.logicalXDPISVGElement.xmlbaseSVGGraphicsElement.farthestViewportElementSVGGraphicsElement.getTransformToElementSVGGraphicsElement.nearestViewportElementSVGStylableSVGTests.hasExtensionSVGTests.requiredFeaturesSyncEventInitValidateAssertionCallbackWebKitDirectoryEntryWebKitDirectoryReaderWebKitEntriesCallbackWebKitEntryWebKitErrorCallbackWebKitFileCallbackWebKitFileEntryWebKitFileSystemWindow.clearImmediateWindow.msSetImmediateWindow.setImmediate
If your run-time guarantees that some of these names are available at run-time (e.g. for an IE-only app), add the declarations locally in your project, e.g.:
ForElement.msMatchesSelector, add the following to a localdom.ie.d.ts
interfaceElement{msMatchesSelector(selectors:string):boolean;}
Similarly, to addclearImmediate andsetImmediate, you can add a declaration forWindow in your localdom.ie.d.ts:
interfaceWindow{clearImmediate(handle:number):void;setImmediate(handler:(...args:any[])=>void):number;setImmediate(handler:any, ...args:any[]):number;}
The following code will now complain aboutx no longer being callable:
functionfoo<T>(x:T|(()=>string)){if(typeofx==="function"){x();// ~~~// Cannot invoke an expression whose type lacks a call signature. Type '(() => string) | (T & Function)' has no compatible call signatures.}}
This is because, unlike previously whereT would be narrowed away, it is nowexpanded intoT & Function. However, because this type has no call signatures declared, the type system won't find any common call signature betweenT & Function and() => string.
Instead, consider using a more specific type than{} orObject, and consider adding additional constraints to what you expectT might be.
unknown is now a reserved type name, as it is now a built-in type. Depending on your intended use ofunknown, you may want to remove the declaration entirely (favoring the newly introducedunknown type), or rename it to something else.
In the following example,A has the typenull andB has the typeundefined whenstrictNullChecks is turned off:
typeA={a:number}&null;// nulltypeB={a:number}&undefined;// undefined
This is because TypeScript 3.0 is better at reducing subtypes and supertypes in intersection and union types respectively; however, becausenull andundefined are both considered subtypes of every other type whenstrictNullChecks is off, an intersection with some object type and either will always reduce tonull orundefined.
If you were relying onnull andundefined to be"identity" elements under intersections, you should look for a way to useunknown instead ofnull orundefined wherever they appeared
TypeScript 2.9 generalizes index types to includenumber andsymbol named properties. Previously, thekeyof operator and mapped types only supportedstring named properties.
functionuseKey<T,KextendskeyofT>(o:T,k:K){varname:string=k;// Error: keyof T is not assignable to string}
If your functions are only able to handle string named property keys, use
Extract<keyof T, string>in the declaration:functionuseKey<T,KextendsExtract<keyofT,string>>(o:T,k:K){varname:string=k;// OK}
If your functions are open to handling all property keys, then the changes should be done down-stream:
functionuseKey<T,KextendskeyofT>(o:T,k:K){varname:string|number|symbol=k;}
Otherwise use
--keyofStringsOnlycompiler option to disable the new behavior.
The following code is a compiler error as of#22262:
functionf(a:number, ...b:number[],// Illegal trailing comma){}
Trailing commas on rest parameters are not valid JavaScript, and the syntax is now an error in TypeScript too.
The following code is a compiler error understrictNullChecks as of#24013:
functionf<T>(x:T){consty:object|null|undefined=x;}
It may be fulfilled with any type (eg,string ornumber), so it was incorrect to allow. If you encounter this issue, either constrain your type parameter toobject to only allow object types for it, or compare against{} instead ofobject (if the intent was to allow any type).
As per#20568, unused type parameters were previously reported under--noUnusedLocals, but are now instead reported under--noUnusedParameters.
Some MS-specific types are removed from the DOM definition to better align with the standard. Types removed include:
MSAppMSAppAsyncOperationMSAppAsyncOperationEventMapMSBaseReaderMSBaseReaderEventMapMSExecAtPriorityFunctionCallbackMSHTMLWebViewElementMSManipulationEventMSRangeCollectionMSSiteModeEventMSUnsafeFunctionCallbackMSWebViewAsyncOperationMSWebViewAsyncOperationEventMapMSWebViewSettings
As per#21386, the DOM libraries have been updated to reflect the WHATWG standard.
If you need to continue using thealt attribute, consider reopeningHTMLObjectElement via interface merging in the global scope:
// Must be in a global .ts file or a 'declare global' block.interfaceHTMLObjectElement{alt:string;}
For a full list of breaking changes see thebreaking change issues.
The following code used to have no compile errors:
varpair:[number,number]=[1,2];vartriple:[number,number,number]=[1,2,3];pair=triple;
However, thiswas an error:
triple=pair;
Now both assignments are an error.This is because tuples now have a length property whose type is their length.Sopair.length: 2, buttriple.length: 3.
Note that certain non-tuple patterns were allowed previously, but are no longer allowed:
conststruct:[string,number]=['key'];for(constnofnumbers){struct.push(n);}
The best fix for this is to make your own type that extends Array:
interfaceStructextendsArray<string|number>{'0':string;'1'?:number;}conststruct:Struct=['key'];for(constnofnumbers){struct.push(n);}
UnderallowSyntheticDefaultImports, types for default imports are synthesized less often for TS and JS files
In the past, we'd synthesize a default import in the typesystem for a TS or JS file written like so:
exportconstfoo=12;
meaning the module would have the type{foo: number, default: {foo: number}}.This would be wrong, because the file would be emitted with an__esModule marker, so no popular module loader would ever create a synthetic default for it when loading the file, and thedefault member that the typesystem inferred was there would never exist at runtime. Now that we emulate this synthetic default behavior in our emit under theESModuleInterop flag, we've tightened the typechecker behavior to match the shape you'd expect to see at runtime. Without the intervention of other tools at runtime, this change should only point out mistakenly incorrect import default usages which should be changed to namespace imports.
Previously the constraint of an indexed access type was only computed if the type had an index signature, otherwise it wasany. That allowed invalid assignments to go unchecked. In TS 2.7.1, the compiler is a bit smarter here, and will compute the constraint to be the union of all possible properties here.
interfaceO{foo?:string;}functionfails<KextendskeyofO>(o:O,k:K){vars:string=o[k];// Previously allowed, now an error// string | undefined is not assignable to a string}
For an in x expression, wheren is a string literal or string literal type andx is a union type, the "true" branch narrows to types which have an optional or required propertyn, and the "false" branch narrows to types which have an optional or missing propertyn. This may result in cases where the type of a variable is narrowed tonever in the false branch if the type is declared to always have the the propertyn.
varx:{foo:number};if("foo"inx){x;// { foo: number }}else{x;// never}
Previously classes that were structurally equivalent were reduced to their best common type in a conditional or|| operator. Now these classes are maintained in a union type to allow for more accurate checking forinstanceof operators.
classAnimal{}classDog{park(){}}vara=Math.random() ?newAnimal() :newDog();// typeof a now Animal | Dog, previously Animal
CustomEvent now has a type parameter for the type of thedetails property. If you are extending from it, you will need to specify an additional type parameter.
classMyCustomEventextendsCustomEvent{}
should become
classMyCustomEventextendsCustomEvent<any>{}
For full list of breaking changes see thebreaking change issues.
The following code used to have no compile errors:
functionf(n:number){n=0;}classC{privatem:number;constructor(){this.m=0;}}
Now when the--noUnusedLocals and--noUnusedParameterscompiler options are enabled, bothn andm will be marked as unused, because their values are neverread. Previously TypeScript would only check whether their values werereferenced.
Also recursive functions that are only called within their own bodies are considered unused.
functionf(){f();// Error: 'f' is declared but its value is never read}
Previously, constructs like
declare module"foo"{exportdefault"some"+"string";}
was not flagged as an error in ambient contexts. Expressions are generally forbidden in declaration files and ambient modules, as things liketypeof have unclear intent, so this was inconsistent with our handling of executable code elsewhere in these contexts. Now, anything which is not an identifier or qualified name is flagged as an error. The correct way to make a DTS for a module with the value shape described above would be like so:
declare module"foo"{const_default:string;exportdefault_default;}
The compiler already generated definitions like this, so this should only be an issue for definitions which were written by hand.
For full list of breaking changes see thebreaking change issues.
TypeScript 2.4 introduces the concept of "weak types".Any type that contains nothing but a set of all-optional properties is considered to beweak.For example, thisOptions type is a weak type:
interfaceOptions{data?:string,timeout?:number,maxRetries?:number,}
In TypeScript 2.4, it's now an error to assign anything to a weak type when there's no overlap in properties.For example:
functionsendMessage(options:Options){// ...}constopts={payload:"hello world!",retryOnFail:true,}// Error!sendMessage(opts);// No overlap between the type of 'opts' and 'Options' itself.// Maybe we meant to use 'data'/'maxRetries' instead of 'payload'/'retryOnFail'.
Recommendation
- Declare the properties if they really do exist.
- Add an index signature to the weak type (i.e.
[propName: string]: {}). - Use a type assertion (i.e.
opts as Options).
TypeScript can now make inferences from contextual types to the return type of a call.This means that some code may now appropriately error.As an example of a new errors you might spot as a result:
letx:Promise<string>=newPromise(resolve=>{resolve(10);// ~~ Error! Type 'number' is not assignable to 'string'.});
TypeScript's checking of callback parameters is now covariant with respect to immediate signature checks.Previously it was bivariant, which could sometimes let incorrect types through.Basically, this means that callback parameters and classes thatcontain callbacks are checked more carefully, so Typescript willrequire stricter types in this release.This is particularly true of Promises and Observables due to the way in which their APIs are specified.
Here is an example of improved Promise checking:
letp=newPromise((c,e)=>{c(12)});letu:Promise<number>=p;~Type 'Promise<{}>' is not assignable to 'Promise<number>'
The reason this occurs is that TypeScript is not able to infer the type argumentT when you callnew Promise.As a result, it just infersPromise<{}>.Unfortunately, this allows you to writec(12) andc('foo'), even though the declaration ofp explicitly says that it must bePromise<number>.
Under the new rules,Promise<{}> is not assignable toPromise<number> because it breaks the callbacks to Promise.TypeScript still isn't able to infer the type argument, so to fix this you have to provide the type argument yourself:
letp:Promise<number>=newPromise<number>((c,e)=>{c(12)});// ^^^^^^^^ explicit type arguments here
This requirement helps find errors in the body of the promise code.Now if you mistakenly callc('foo'), you get the following error:
letp:Promise<number>=newPromise<number>((c,e)=>{c('foo')});// ~~~~~// Argument of type '"foo"' is not assignable to 'number'
Other callbacks are affected by the improved callback checking aswell, primarily nested callbacks. Here's an example with a functionthat takes a callback, which takes a nested callback. The nestedcallback is now checked co-variantly.
declarefunctionf(callback:(nested:(error:number,result:any)=>void,index:number)=>void):void;f((nested:(error:number)=>void)=>{log(error)});~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'(error: number) => void'isnotassignableto(error:number,result: any)=>void'
The fix is easy in this case. Just add the missing parameter to thenested callback:
f((nested:(error:number,result:any)=>void)=>{});
TypeScript now tries to unify type parameters when comparing two single-signature types.As a result, you'll get stricter checks when relating two generic signatures, and may catch some bugs.
typeA=<T,U>(x:T,y:U)=>[T,U];typeB=<S>(x:S,y:S)=>[S,S];functionf(a:A,b:B){a=b;// Errorb=a;// Ok}
Recommendation
Either correct the definition or use--noStrictGenericChecks.
Prior to TypeScript 2.4, in the following example
letf:<T>(x:T)=>T=y=>y;
y would have the typeany.This meant the program would type-check, but you could technically do anything withy, such as the following:
letf:<T>(x:T)=>T=y=>y()+y.foo.bar;
Recommendation: Appropriately re-evaluate whether your generics have the correct constraint, or are even necessary. As a last resort, annotate your parameters with theany type.
For full list of breaking changes see thebreaking change issues.
Example
classX<>{}// Error: Type parameter list cannot be empty.functionf<>(){}// Error: Type parameter list cannot be empty.constx:X<>=newX<>();// Error: Type parameter list cannot be empty.
For full list of breaking changes see thebreaking change issues.
Standard library now has declarations for
Window.fetch; dependencies to@types\whatwg-fetchwill cause conflicting declaration errors and will need to be removed.Standard library now has declarations for
ServiceWorker; dependencies on@types\service_worker_apiwill cause conflicting declaration errors and will need to be removed.
For full list of breaking changes see thebreaking change issues.
In ES2015, constructors which return an object implicitly substitute the value ofthis for any callers ofsuper(...).As a result, it is necessary to capture any potential return value ofsuper(...) and replace it withthis.
Example
A classC as:
classCextendsB{publica:number;constructor(){super();this.a=0;}}
Will generate code as:
varC=(function(_super){__extends(C,_super);functionC(){var_this=_super.call(this)||this;_this.a=0;return_this;}returnC;}(B));
Notice:
_super.call(this)is captured into a local variable_this- All uses of
thisin the constructor body has been replaced by the result of thesupercall (i.e._this) - Each constructor now returns explicitly its
this, to enable for correct inheritance
It is worth noting that the use ofthis beforesuper(...) is already an error as ofTypeScript 1.8
As part of substituting the value ofthis with the value returned by asuper(...) call, subclassingError,Array, and others may no longer work as expected.This is due to the fact that constructor functions forError,Array, and the like use ECMAScript 6'snew.target to adjust the prototype chain;however, there is no way to ensure a value fornew.target when invoking a constructor in ECMAScript 5.Other downlevel compilers generally have the same limitation by default.
Example
For a subclass like the following:
classFooErrorextendsError{constructor(m:string){super(m);}sayHello(){return"hello "+this.message;}}
you may find that:
- methods may be
undefinedon objects returned by constructing these subclasses, so callingsayHellowill result in an error. instanceofwill be broken between instances of the subclass and their instances, so(new FooError()) instanceof FooErrorwill returnfalse.
Recommendation
As a recommendation, you can manually adjust the prototype immediately after anysuper(...) calls.
classFooErrorextendsError{constructor(m:string){super(m);// Set the prototype explicitly.Object.setPrototypeOf(this,FooError.prototype);}sayHello(){return"hello "+this.message;}}
However, any subclass ofFooError will have to manually set the prototype as well.For runtimes that don't supportObject.setPrototypeOf, you may instead be able to use__proto__.
Unfortunately,these workarounds will not work on Internet Explorer 10 and prior.One can manually copy methods from the prototype onto the instance itself (i.e.FooError.prototype ontothis), but the prototype chain itself cannot be fixed.
String, numeric, boolean and enum literal types are not inferred by default forconst declarations andreadonly properties. This means your variables/properties an have more narrowed type than before. This could manifest in using comparison operators such as=== and!==.
Example
constDEBUG=true;// Now has type `true`, previously had type `boolean`if(DEBUG===false){/// Error: operator '===' can not be applied to 'true' and 'false' ...}
Recommendation
For types intentionally needed to be wider, cast to the base type:
constDEBUG=<boolean>true;// type is `boolean`
String, numeric and boolean literal types will be inferred if the generic type parameter has a constraint ofstring,number orboolean respectively. Moreover the rule of failing if no best common super-type for inferences in the case of literal types if they have the same base type (e.g.string).
Example
declarefunctionpush<Textendsstring>(...args:T[]):T;varx=push("A","B","C");// inferred as "A" | "B" | "C" in TS 2.1, was string in TS 2.0
Recommendation
Specify the type argument explicitly at call site:
varx=push<string>("A","B","C");// x is string
Previously the compiler silently gave the argument of the callback (c below) a typeany. The reason is how the compiler resolves function expressions while doing overload resolution.Starting with TypeScript 2.1 an error will be reported under--noImplicitAny.
Example
declarefunctionfunc(callback:()=>void):any;declarefunctionfunc(callback:(arg:number)=>void):any;func(c=>{});
Recommendation
Remove the first overload, since it is rather meaningless; the function above can still be called with a call back with 1 or 0 required arguments, as it is safe for functions to ignore additional arguments.
declarefunctionfunc(callback:(arg:number)=>void):any;func(c=>{});func(()=>{});
Alternatively, you can either specify an explicit type annotation on the callback argument:
func((c:number)=>{});
Mostly, this should catch errors that were previously allowed as valid comma expressions.
Example
letx=Math.pow((3,5));// x = NaN, was meant to be `Math.pow(3, 5)`// This code does not do what it appears to!letarr=[];switch(arr.length){case0,1:return'zero or one';default:return'more than one';}
Recommendation
--allowUnreachableCode will disable the warning for the whole compilation. Alternatively, you can use thevoid operator to suppress the error for specific comma expressions:
leta=0;lety=(voida,1);// no warning for `a`
- Node.firstChild,Node.lastChild,Node.nextSibling,Node.previousSibling,Node.parentElement andNode.parentNode are now
Node | nullinstead ofNode.
See#11113 for more details.
Recommendation is to explicitly check fornull or use the! assertion operator (e.g.node.lastChild!).
For full list of breaking changes see thebreaking change issues.
Type narrowing does not cross function and class expressions, as well as lambda expressions.
Example
varx:number|string;if(typeofx==="number"){functioninner():number{returnx;// Error, type of x is not narrowed, c is number | string}vary:number=x;// OK, x is number}
In the previous pattern the compiler can not tell when the callback will execute. Consider:
varx:number|string="a";if(typeofx==="string"){setTimeout(()=>console.log(x.charAt(0)),0);}x=5;
It is wrong to assumex is astring whenx.charAt() is called, as indeed it isn't.
Recommendation
Use constants instead:
constx:number|string="a";if(typeofx==="string"){setTimeout(()=>console.log(x.charAt(0)),0);}
Example
functiong<T>(obj:T){vart:T;if(objinstanceofRegExp){t=obj;// RegExp is not assignable to T}}
RecommendationEither declare your locals to be a specific type and not the generic type parameter, or use a type assertion.
Example
classC{getx(){return0;}}varc=newC();c.x=1;// Error Left-hand side is a readonly property
Recommendation
Define a setter or do not write to the property.
This is already a run-time error under strict mode. Starting with TypeScript 2.0, it will be flagged as a compile-time error as well.
Example
if(true){functionfoo(){}}export=foo;
Recommendation
Use function expressions instead:
if(true){constfoo=function(){}}
ES2015 tagged templates always pass their tag an immutable array-like object that has a property calledraw (which is also immutable).TypeScript names this object theTemplateStringsArray.
Conveniently,TemplateStringsArray was assignable to anArray<string>, so it's possible users took advantage of this to use a shorter type for their tag parameters:
functionmyTemplateTag(strs:string[]){// ...}
However, in TypeScript 2.0, the language now supports thereadonly modifier and can express that these objects are immutable.As a result,TemplateStringsArray has also been made immutable, and is no longer assignable tostring[].
Recommendation
UseTemplateStringsArray explicitly (or useReadonlyArray<string>).
For full list of breaking changes see thebreaking change issues.
Modules were always parsed in strict mode as per ES6, but for non-ES6 targets this was not respected in the generated code. Starting with TypeScript 1.8, emitted modules are always in strict mode. This shouldn't have any visible changes in most code as TS considers most strict mode errors as errors at compile time, but it means that some things which used to silently fail at runtime in your TS code, like assigning toNaN, will now loudly fail. You can reference theMDN Article on strict mode for a detailed list of the differences between strict mode and non-strict mode.
To disable this behavior, pass--noImplicitUseStrict on the command line or set it in your tsconfig.json file.
In accordance with the ES6/ES2015 spec, it is an error to export a non-local name from a module.
Example
export{Promise};// Error
Recommendation
Use a local variable declaration to capture the global name before exporting it.
constlocalPromise=Promise;export{localPromiseasPromise};
In TypeScript 1.8 we've added a set ofreachability checks to prevent certain categories of errors. Specifically
check if code is reachable (enabled by default, can be disabled via
allowUnreachableCodecompiler option)functiontest1(){return1;return2;// error here}functiontest2(x){if(x){return1;}else{thrownewError("NYI")}vary=1;// error here}
check if label is unused (enabled by default, can be disabled via
allowUnusedLabelscompiler option)l:// error will be reported - label `l` is unusedwhile(true){}(x)=>{x:x}// error will be reported - label `x` is unused
check if all code paths in function with return type annotation return some value (disabled by default, can be enabled via
noImplicitReturnscompiler option)// error will be reported since function does not return anything explicitly when `x` is falsy.functiontest(x):number{if(x)return10;}
check if control flow falls through cases in switch statement (disabled by default, can be enabled via
noFallthroughCasesInSwitchcompiler option). Note that cases without statements are not reported.switch(x){// OKcase1:case2:return1;}switch(x){case1:if(y)return1;case2:return2;}
If these errors are showing up in your code and you still think that scenario when they appear is legitimate you can suppress errors with compiler options.
Previously specifying both while using modules would result in an emptyout file and no error.
- ImageData.data is now of type
Uint8ClampedArrayinstead ofnumber[]. See#949 for more details. - HTMLSelectElement .options is now of type
HTMLCollectioninstead ofHTMLSelectElement. See#1558 for more details. - HTMLTableElement.createCaption,HTMLTableElement.createTBody,HTMLTableElement.createTFoot,HTMLTableElement.createTHead,HTMLTableElement.insertRow,HTMLTableSectionElement.insertRow, andHTMLTableElement.insertRow now return
HTMLTableRowElementinstead ofHTMLElement. See#3583 for more details. - HTMLTableRowElement.insertCell now return
HTMLTableCellElementinstead ofHTMLElement. See#3583 for more details. - IDBObjectStore.createIndex andIDBDatabase.createIndex second argument is now of type
IDBObjectStoreParametersinstead ofany. See#5932 for more details. - DataTransferItemList.Item returns type now is
DataTransferIteminstead ofFile. See#6106 for more details. - Window.open return type now is
Windowinstead ofany. See#6418 for more details. - WeakMap.clear as removed. See#6500 for more details.
ES6 disallows accessingthis in a constructor declaration.
For example:
classB{constructor(that?:any){}}classCextendsB{constructor(){super(this);// error;}}classDextendsB{private_prop1:number;constructor(){this._prop1=10;// errorsuper();}}
For full list of breaking changes see thebreaking change issues.
In a class, the type of the valuethis will be inferred to thethis type.This means subsequent assignments from values the original type can fail.
Example:
classFighter{/**@returns the winner of the fight. */fight(opponent:Fighter){lettheVeryBest=this;if(Math.rand()<0.5){theVeryBest=opponent;// error}returntheVeryBest}}
Recommendations:
Add a type annotation:
classFighter{/**@returns the winner of the fight. */fight(opponent:Fighter){lettheVeryBest:Fighter=this;if(Math.rand()<0.5){theVeryBest=opponent;// no error}returntheVeryBest}}
The keywordsabstract, public, protected andprivate areFutureReservedWords in ECMAScript 3 and are subject to automatic semicolon insertion. Previously, TypeScript did not insert semicolons when these keywords were on their own line. Now that this is fixed,abstract class D no longer correctly extendsC in the following example, and instead declares a concrete methodm and an additional property namedabstract.
Note thatasync anddeclare already correctly did ASI.
Example:
abstractclassC{abstractm():number;}abstractclassDextendsC{abstractm():number;}
Recommendations:
Remove line breaks after keywords when defining class members. In general, avoid relying on automatic semicolon insertion.
For full list of breaking changes see thebreaking change issues.
It is an error to specify properties in an object literal that were not specified on the target type, when assigned to a variable or passed for a parameter of a non-empty target type.
This new strictness can be disabled with the--suppressExcessPropertyErrors compiler option.
Example:
varx:{foo:number};x={foo:1,baz:2};// Error, excess property `baz`vary:{foo:number,bar?:number};y={foo:1,baz:2};// Error, excess or misspelled property `baz`
Recommendations:
To avoid the error, there are few remedies based on the situation you are looking into:
If the target type accepts additional properties, add an indexer:
varx:{foo:number,[x:string]:any};x={foo:1,baz:2};// OK, `baz` matched by index signature
If the source types are a set of related types, explicitly specify them using union types instead of just specifying the base type.
letanimalList:(Dog|Cat|Turkey)[]=[// use union type instead of Animal{name:"Milo",meow:true},{name:"Pepper",bark:true},{name:"koko",gobble:true}];
Otherwise, explicitly cast to the target type to avoid the warning message:
interfaceFoo{foo:number;}interfaceFooBar{foo:number;bar:number;}vary:Foo;y=<FooBar>{foo:1,bar:2};
Previously, for the filesone.ts andtwo.ts, an import of"one" intwo.ts would resolve toone.ts if they resided in the same directory.
In TypeScript 1.6,"one" is no longer equivalent to "./one" when compiling with CommonJS. Instead, it is searched as relative to an appropriatenode_modules folder as would be resolved by runtimes such as Node.js. For details, seethe issue that describes the resolution algorithm.
Example:
./one.ts
exportfunctionf(){return10;}
./two.ts
import{fasg}from"one";
Recommendations:
Fix any non-relative import names that were unintended (strongly suggested).
./one.ts
exportfunctionf(){return10;}
./two.ts
import{fasg}from"./one";
Set the--moduleResolution compiler option toclassic.
Function and class default export declarations can no longer merge with entities intersecting in their meaning
Declaring an entity with the same name and in the same space as a default export declaration is now an error; for example,
exportdefaultfunctionfoo(){}namespacefoo{varx=100;}
and
exportdefaultclassFoo{a:number;}interfaceFoo{b:string;}
both cause an error.
However, in the following example, merging is allowed because the namespace does does not have a meaning in the value space:
exportdefaultclassFoo{}namespaceFoo{}
Recommendations:
Declare a local for your default export and use a separateexport default statement as so:
classFoo{a:number;}interfacefoo{b:string;}exportdefaultFoo;
For more details seethe originating issue.
In accordance withthe ES6 spec, module bodies are now parsed in strict mode. module bodies will behave as if"use strict" was defined at the top of their scope; this includes flagging the use ofarguments andeval as variable or parameter names, use of future reserved words as variables or parameters, use of octal numeric literals, etc..
- MessageEvent andProgressEvent constructors now expect arguments; seeissue #4295 for more details.
- ImageData constructor now expects arguments; seeissue #4220 for more details.
- File constructor now expects arguments; seeissue #3999 for more details.
The compiler uses thenew bulk-export variation of the_export function in the System module format that takes any object containing key value pairs (optionally an entire module object for export *) as arguments instead of key, value.
The module loader needs to be updated tov0.17.1 or higher.
Entry point of TypeScript npm package was moved frombin tolib to unblock scenarios when 'node_modules/typescript/bin/typescript.js' is served from IIS (by defaultbin is in the list of hidden segments so IIS will block access to this folder).
TypeScript 1.6 removes thepreferGlobal flag from package.json. If you rely on this behaviour please usenpm install -g typescript.
Starting with 1.6, decorators type checking is more accurate; the compiler will checks a decorator expression as a call expression with the decorated entity as a parameter. This can cause error to be reported that were not in previous releases.
For full list of breaking changes see thebreaking change issues.
This is an alignment with the ES6 semantics of arrow functions. Previously arguments within an arrow function would bind to the arrow function arguments. As perES6 spec draft 9.2.12, arrow functions do not have an arguments objects.In TypeScript 1.5, the use of arguments object in arrow functions will be flagged as an error to ensure your code ports to ES6 with no change in semantics.
Example:
functionf(){return()=>arguments;// Error: The 'arguments' object cannot be referenced in an arrow function.}
Recommendations:
// 1. Use named rest argsfunctionf(){return(...args)=>{args;}}// 2. Use function expressions insteadfunctionf(){returnfunction(){arguments;}}
For regular enums, pre 1.5, the compileronly inline constant members, and a member was only constant if its initializer was a literal. That resulted in inconsistent behavior depending on whether the enum value is initialized with a literal or an expression. Starting with Typescript 1.5 all non-const enum members are not inlined.
Example:
varx=E.a;// previously inlined as "var x = 1; /*E.a*/"enumE{a=1}
Recommendation:Add theconst modifier to the enum declaration to ensure it is consistently inlined at all consumption sites.
For more details see issue#2183.
Prior to this release, contextual types did not flow through parenthesized expressions. This has forced explicit type casts, especially in cases where parentheses arerequired to make an expression parse.
In the examples below,m will have a contextual type, where previously it did not.
varx:SomeType=(n)=>((m)=>q);vary:SomeType=t ?(m=>m.length) :undefined;classCextendsCBase<string>{constructor(){super({method(m){returnm.length;}});}}
See issues#1425 and#920 for more details.
TypeScript 1.5 refreshes the DOM types in lib.d.ts. This is the first major refresh since TypeScript 1.0; many IE-specific definitions have been removed in favor of the standard DOM definitions, as well as adding missing types like Web Audio and touch events.
Workaround:
You can keep using older versions of the library with newer version of the compiler. You will need to include a local copy of a previous version in your project. Here is thelast released version before this change (TypeScript 1.5-alpha).
Here is a list of changes:
- Property
selectionis removed from typeDocument - Property
clipboardDatais removed from typeWindow - Removed interface
MSEventAttachmentTarget - Properties
onresize,disabled,uniqueID,removeNode,fireEvent,currentStyle,runtimeStyleare removed from typeHTMLElement - Property
urlis removed from typeEvent - Properties
execScript,navigate,itemare removed from typeWindow - Properties
documentMode,parentWindow,createEventObjectare removed from typeDocument - Property
parentWindowis removed from typeHTMLDocument - Property
setCapturedoes not exist anywhere now - Property
releaseCapturedoes not exist anywhere now - Properties
setAttribute,styleFloat,pixelLeftare removed from typeCSSStyleDeclaration - Property
selectorTextis removed from typeCSSRule CSSStyleSheet.rulesis of typeCSSRuleListinstead ofMSCSSRuleListdocumentElementis of typeElementinstead ofHTMLElementEventhas a new required propertyreturnValueNodehas a new required propertybaseURIElementhas a new required propertyclassListLocationhas a new required propertyorigin- Properties
MSPOINTER_TYPE_MOUSE,MSPOINTER_TYPE_TOUCHare removed from typeMSPointerEvent CSSStyleRulehas a new required propertyreadonly- Property
execUnsafeLocalFunctionis removed from typeMSApp - Global method
toStaticHTMLis removed HTMLCanvasElement.getContextnow returnsCanvasRenderingContext2D | WebGLRenderingContex- Removed extension types
Dataview,Weakmap,Map,Set XMLHttpRequest.sendhas two overloadssend(data?: Document): void;andsend(data?: String): void;window.orientationis of typestringinstead ofnumber- IE-specific
attachEventanddetachEventare removed fromWindow
Here is a list of libraries that are partly or entirely replaced by the added DOM types:
DefinitelyTyped/auth0/auth0.d.tsDefinitelyTyped/gamepad/gamepad.d.tsDefinitelyTyped/interactjs/interact.d.tsDefinitelyTyped/webaudioapi/waa.d.tsDefinitelyTyped/webcrypto/WebCrypto.d.ts
For more details, please see thefull change.
In accordance withthe ES6 spec, class bodies are now parsed in strict mode. Class bodies will behave as if"use strict" was defined at the top of their scope; this includes flagging the use ofarguments andeval as variable or parameter names, use of future reserved words as variables or parameters, use of octal numeric literals, etc..
For full list of breaking changes see thebreaking change issues.
Seeissue #868 for more details about breaking changes related to Union Types
Given multiple viable candidates from a Best Common Type computation we now choose an item (depending on the compiler's implementation) rather than the first item.
vara:{x:number;y?:number};varb:{x:number;z?:number};// was { x: number; z?: number; }[]// now { x: number; y?: number; }[]varbs=[b,a];
This can happen in a variety of circumstances. A shared set of required properties and a disjoint set of other properties (optional or otherwise), empty types, compatible signature types (including generic and non-generic signatures when type parameters are stamped out withany).
RecommendationProvide a type annotation if you need a specific type to be chosen
varbs:{x:number;y?:number;z?:number}[]=[b,a];
Using different types for multiple arguments of type T is now an error, even with constraints involved:
declarefunctionfoo<T>(x:T,y:T):T;varr=foo(1,"");// r used to be {}, now this is an error
With constraints:
interfaceAnimal{x}interfaceGiraffeextendsAnimal{y}interfaceElephantextendsAnimal{z}functionf<TextendsAnimal>(x:T,y:T):T{returnundefined;}varg:Giraffe;vare:Elephant;f(g,e);
Seehttps://github.com/Microsoft/TypeScript/pull/824#discussion_r18665727 for explanation.
RecommendationsSpecify an explicit type parameter if the mismatch was intentional:
varr=foo<{}>(1,"");// Emulates 1.0 behaviorvarr=foo<string|number>(1,"");// Most usefulvarr=foo<any>(1,"");// Easiestf<Animal>(g,e);
or rewrite the function definition to specify that mismatches are OK:
declarefunctionfoo<T,U>(x:T,y:U):T|U;functionf<TextendsAnimal,UextendsAnimal>(x:T,y:U):T|U{returnundefined;}
You cannot use heterogeneous argument types anymore:
functionmakeArray<T>(...items:T[]):T[]{returnitems;}varr=makeArray(1,"");// used to return {}[], now an error
Likewise fornew Array(...)
RecommendationsDeclare a back-compatible signature if the 1.0 behavior was desired:
functionmakeArray<T>(...items:T[]):T[];functionmakeArray(...items:{}[]):{}[];functionmakeArray<T>(...items:T[]):T[]{returnitems;}
varf10:<T>(x:T,b:()=>(a:T)=>void,y:T)=>T;varr9=f10('',()=>(a=>a.foo),1);// r9 was any, now this is an error
RecommendationsManually specify a type parameter
varr9=f10<any>('',()=>(a=>a.foo),1);
ECMAScript 2015 Language Specification (ECMA-262 6th Edition) specifies thatClassDeclaration andClassExpression are strict mode productions.Thus, additional restrictions will be applied when parsing a class declaration or class expression.
Examples:
classimplements{}// Invalid: implements is a reserved word in strict modeclassC{foo(arguments:any){// Invalid: "arguments" is not allow as a function argumentvareval=10;// Invalid: "eval" is not allowed as the left-hand-side expressionarguments=[];// Invalid: arguments object is immutable}}
For complete list of strict mode restrictions, please see Annex C - The Strict Mode of ECMAScript of ECMA-262 6th Edition.
For full list of breaking changes see thebreaking change issues.
Examples:
varResultIsNumber17=+(null+undefined);// Operator '+' cannot be applied to types 'undefined' and 'undefined'.varResultIsNumber18=+(null+null);// Operator '+' cannot be applied to types 'null' and 'null'.varResultIsNumber19=+(undefined+undefined);// Operator '+' cannot be applied to types 'undefined' and 'undefined'.
Similarly, using null and undefined directly as objects that have methods now is an error
Examples:
null.toBAZ();undefined.toBAZ();
News
Debugging TypeScript
- Performance
- Performance-Tracing
- Debugging-Language-Service-in-VS-Code
- Getting-logs-from-TS-Server-in-VS-Code
- JavaScript-Language-Service-in-Visual-Studio
- Providing-Visual-Studio-Repro-Steps
Contributing to TypeScript
- Contributing to TypeScript
- TypeScript Design Goals
- Coding Guidelines
- Useful Links for TypeScript Issue Management
- Writing Good Design Proposals
- Compiler Repo Notes
- Deployment
Building Tools for TypeScript
- Architectural Overview
- Using the Compiler API
- Using the Language Service API
- Standalone Server (tsserver)
- TypeScript MSBuild In Depth
- Debugging Language Service in VS Code
- Writing a Language Service Plugin
- Docker Quickstart
FAQs
The Main Repo