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 the [[API Breaking Changes]] page.
wheelDeltaX
, wheelDelta
, and wheelDeltaZ
have all been removed as they is a deprecated properties on WheelEvent
s.
Solution: Use deltaX
, deltaY
, and deltaZ
instead.
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.mozImageSmoothingEnabled
CanvasRenderingContext2D.msFillRule
CanvasRenderingContext2D.oImageSmoothingEnabled
CanvasRenderingContext2D.webkitImageSmoothingEnabled
Document.caretRangeFromPoint
Document.createExpression
Document.createNSResolver
Document.execCommandShowHelp
Document.exitFullscreen
Document.exitPointerLock
Document.focus
Document.fullscreenElement
Document.fullscreenEnabled
Document.getSelection
Document.msCapsLockWarningOff
Document.msCSSOMElementFloatMetrics
Document.msElementsFromRect
Document.msElementsFromPoint
Document.onvisibilitychange
Document.onwebkitfullscreenchange
Document.onwebkitfullscreenerror
Document.pointerLockElement
Document.queryCommandIndeterm
Document.URLUnencoded
Document.webkitCurrentFullScreenElement
Document.webkitFullscreenElement
Document.webkitFullscreenEnabled
Document.webkitIsFullScreen
Document.xmlEncoding
Document.xmlStandalone
Document.xmlVersion
DocumentType.entities
DocumentType.internalSubset
DocumentType.notations
DOML2DeprecatedSizeProperty
Element.msContentZoomFactor
Element.msGetUntransformedBounds
Element.msMatchesSelector
Element.msRegionOverflow
Element.msReleasePointerCapture
Element.msSetPointerCapture
Element.msZoomTo
Element.onwebkitfullscreenchange
Element.onwebkitfullscreenerror
Element.webkitRequestFullScreen
Element.webkitRequestFullscreen
ElementCSSInlineStyle
ExtendableEventInit
ExtendableMessageEventInit
FetchEventInit
GenerateAssertionCallback
HTMLAnchorElement.Methods
HTMLAnchorElement.mimeType
HTMLAnchorElement.nameProp
HTMLAnchorElement.protocolLong
HTMLAnchorElement.urn
HTMLAreasCollection
HTMLHeadElement.profile
HTMLImageElement.msGetAsCastingSource
HTMLImageElement.msGetAsCastingSource
HTMLImageElement.msKeySystem
HTMLImageElement.msPlayToDisabled
HTMLImageElement.msPlayToDisabled
HTMLImageElement.msPlayToPreferredSourceUri
HTMLImageElement.msPlayToPreferredSourceUri
HTMLImageElement.msPlayToPrimary
HTMLImageElement.msPlayToPrimary
HTMLImageElement.msPlayToSource
HTMLImageElement.msPlayToSource
HTMLImageElement.x
HTMLImageElement.y
HTMLInputElement.webkitdirectory
HTMLLinkElement.import
HTMLMetaElement.charset
HTMLMetaElement.url
HTMLSourceElement.msKeySystem
HTMLStyleElement.disabled
HTMLSummaryElement
MediaQueryListListener
MSAccountInfo
MSAudioLocalClientEvent
MSAudioLocalClientEvent
MSAudioRecvPayload
MSAudioRecvSignal
MSAudioSendPayload
MSAudioSendSignal
MSConnectivity
MSCredentialFilter
MSCredentialParameters
MSCredentials
MSCredentialSpec
MSDCCEvent
MSDCCEventInit
MSDelay
MSDescription
MSDSHEvent
MSDSHEventInit
MSFIDOCredentialParameters
MSIceAddrType
MSIceType
MSIceWarningFlags
MSInboundPayload
MSIPAddressInfo
MSJitter
MSLocalClientEvent
MSLocalClientEventBase
MSNetwork
MSNetworkConnectivityInfo
MSNetworkInterfaceType
MSOutboundNetwork
MSOutboundPayload
MSPacketLoss
MSPayloadBase
MSPortRange
MSRelayAddress
MSSignatureParameters
MSStatsType
MSStreamReader
MSTransportDiagnosticsStats
MSUtilization
MSVideoPayload
MSVideoRecvPayload
MSVideoResolutionDistribution
MSVideoSendPayload
NotificationEventInit
PushEventInit
PushSubscriptionChangeInit
RTCIdentityAssertionResult
RTCIdentityProvider
RTCIdentityProviderDetails
RTCIdentityValidationResult
Screen.deviceXDPI
Screen.logicalXDPI
SVGElement.xmlbase
SVGGraphicsElement.farthestViewportElement
SVGGraphicsElement.getTransformToElement
SVGGraphicsElement.nearestViewportElement
SVGStylable
SVGTests.hasExtension
SVGTests.requiredFeatures
SyncEventInit
ValidateAssertionCallback
WebKitDirectoryEntry
WebKitDirectoryReader
WebKitEntriesCallback
WebKitEntry
WebKitErrorCallback
WebKitFileCallback
WebKitFileEntry
WebKitFileSystem
Window.clearImmediate
Window.msSetImmediate
Window.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.:
For Element.msMatchesSelector
, add the following to a local dom.ie.d.ts
interface Element {
msMatchesSelector(selectors: string): boolean;
}
Similarly, to add clearImmediate
and setImmediate
, you can add a declaration for Window
in your local dom.ie.d.ts
:
interface Window {
clearImmediate(handle: number): void;
setImmediate(handler: (...args: any[]) => void): number;
setImmediate(handler: any, ...args: any[]): number;
}
The following code will now complain about x
no longer being callable:
function foo<T>(x: T | (() => string)) {
if (typeof x === "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 where T
would be narrowed away, it is now expanded into T & Function
. However, because this type has no call signatures declared, the type system won't find any common call signature between T & Function
and () => string
.
Instead, consider using a more specific type than {}
or Object
, and consider adding additional constraints to what you expect T
might be.
unknown
is now a reserved type name, as it is now a built-in type. Depending on your intended use of unknown
, you may want to remove the declaration entirely (favoring the newly introduced unknown
type), or rename it to something else.
In the following example, A
has the type null
and B
has the type undefined
when strictNullChecks
is turned off:
type A = { a: number } & null; // null
type B = { a: number } & undefined; // undefined
This is because TypeScript 3.0 is better at reducing subtypes and supertypes in intersection and union types respectively; however, because null
and undefined
are both considered subtypes of every other type when strictNullChecks
is off, an intersection with some object type and either will always reduce to null
or undefined
.
If you were relying on null
and undefined
to be "identity" elements under intersections, you should look for a way to use unknown
instead of null
or undefined
wherever they appeared
TypeScript 2.9 generalizes index types to include number
and symbol
named properties. Previously, the keyof
operator and mapped types only supported string
named properties.
function useKey<T, K extends keyof T>(o: T, k: K) {
var name: 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:function useKey<T, K extends Extract<keyof T, string>>(o: T, k: K) { var name: string = k; // OK }
-
If your functions are open to handling all property keys, then the changes should be done down-stream:
function useKey<T, K extends keyof T>(o: T, k: K) { var name: string | number | symbol = k; }
-
Otherwise use
--keyofStringsOnly
compiler option to disable the new behavior.
The following code is a compiler error as of #22262:
function f(
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 under strictNullChecks
as of #24013:
function f<T>(x: T) {
const y: object | null | undefined = x;
}
It may be fulfilled with any type (eg, string
or number
), so it was incorrect to allow. If you encounter this issue, either constrain your type parameter to object
to only allow object types for it, or compare against {}
instead of object
(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:
MSApp
MSAppAsyncOperation
MSAppAsyncOperationEventMap
MSBaseReader
MSBaseReaderEventMap
MSExecAtPriorityFunctionCallback
MSHTMLWebViewElement
MSManipulationEvent
MSRangeCollection
MSSiteModeEvent
MSUnsafeFunctionCallback
MSWebViewAsyncOperation
MSWebViewAsyncOperationEventMap
MSWebViewSettings
As per #21386, the DOM libraries have been updated to reflect the WHATWG standard.
If you need to continue using the alt
attribute, consider reopening HTMLObjectElement
via interface merging in the global scope:
// Must be in a global .ts file or a 'declare global' block.
interface HTMLObjectElement {
alt: string;
}
For a full list of breaking changes see the breaking change issues.
The following code used to have no compile errors:
var pair: [number, number] = [1, 2];
var triple: [number, number, number] = [1, 2, 3];
pair = triple;
However, this was an error:
triple = pair;
Now both assignments are an error.
This is because tuples now have a length property whose type is their length.
So pair.length: 2
, but triple.length: 3
.
Note that certain non-tuple patterns were allowed previously, but are no longer allowed:
const struct: [string, number] = ['key'];
for (const n of numbers) {
struct.push(n);
}
The best fix for this is to make your own type that extends Array:
interface Struct extends Array<string | number> {
'0': string;
'1'?: number;
}
const struct: Struct = ['key'];
for (const n of numbers) {
struct.push(n);
}
Under allowSyntheticDefaultImports
, 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:
export const foo = 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 the default
member that the typesystem inferred was there would never exist at runtime. Now that we emulate this synthetic default behavior in our emit under the ESModuleInterop
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 was any
. 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.
interface O {
foo?: string;
}
function fails<K extends keyof O>(o: O, k: K) {
var s: string = o[k]; // Previously allowed, now an error
// string | undefined is not assignable to a string
}
For a n in x
expression, where n
is a string literal or string literal type and x
is a union type, the "true" branch narrows to types which have an optional or required property n
, and the "false" branch narrows to types which have an optional or missing property n
. This may result in cases where the type of a variable is narrowed to never
in the false branch if the type is declared to always have the the property n
.
var x: { foo: number };
if ("foo" in x) {
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 for instanceof
operators.
class Animal {
}
class Dog {
park() { }
}
var a = Math.random() ? new Animal() : new Dog();
// typeof a now Animal | Dog, previously Animal
CustomEvent
now has a type parameter for the type of the details
property. If you are extending from it, you will need to specify an additional type parameter.
class MyCustomEvent extends CustomEvent {
}
should become
class MyCustomEvent extends CustomEvent<any> {
}
For full list of breaking changes see the breaking change issues.
The following code used to have no compile errors:
function f(n: number) {
n = 0;
}
class C {
private m: number;
constructor() {
this.m = 0;
}
}
Now when the --noUnusedLocals
and --noUnusedParameters
compiler options are enabled, both n
and m
will be marked as unused, because their values are never read. Previously TypeScript would only check whether their values were referenced.
Also recursive functions that are only called within their own bodies are considered unused.
function f() {
f(); // Error: 'f' is declared but its value is never read
}
Previously, constructs like
declare module "foo" {
export default "some" + "string";
}
was not flagged as an error in ambient contexts. Expressions are generally forbidden in declaration files and ambient modules, as things like typeof
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;
export default _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 the breaking 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 be weak.
For example, this Options
type is a weak type:
interface Options {
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:
function sendMessage(options: Options) {
// ...
}
const opts = {
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:
let x: Promise<string> = new Promise(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 that contain callbacks are checked more carefully, so Typescript will require 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:
let p = new Promise((c, e) => { c(12) });
let u: 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 argument T
when you call new Promise
.
As a result, it just infers Promise<{}>
.
Unfortunately, this allows you to write c(12)
and c('foo')
, even though the declaration of p
explicitly says that it must be Promise<number>
.
Under the new rules, Promise<{}>
is not assignable to
Promise<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:
let p: Promise<number> = new Promise<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 call c('foo')
, you get the following error:
let p: Promise<number> = new Promise<number>((c, e) => { c('foo') });
// ~~~~~
// Argument of type '"foo"' is not assignable to 'number'
Other callbacks are affected by the improved callback checking as well, primarily nested callbacks. Here's an example with a function that takes a callback, which takes a nested callback. The nested callback is now checked co-variantly.
declare function f(
callback: (nested: (error: number, result: any) => void, index: number) => void
): void;
f((nested: (error: number) => void) => { log(error) });
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'(error: number) => void' is not assignable to (error: number, result: any) => void'
The fix is easy in this case. Just add the missing parameter to the nested 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.
type A = <T, U>(x: T, y: U) => [T, U];
type B = <S>(x: S, y: S) => [S, S];
function f(a: A, b: B) {
a = b; // Error
b = a; // Ok
}
Recommendation
Either correct the definition or use --noStrictGenericChecks
.
Prior to TypeScript 2.4, in the following example
let f: <T>(x: T) => T = y => y;
y
would have the type any
.
This meant the program would type-check, but you could technically do anything with y
, such as the following:
let f: <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 the any
type.
For full list of breaking changes see the breaking change issues.
Example
class X<> {} // Error: Type parameter list cannot be empty.
function f<>() {} // Error: Type parameter list cannot be empty.
const x: X<> = new X<>(); // Error: Type parameter list cannot be empty.
For full list of breaking changes see the breaking change issues.
-
Standard library now has declarations for
Window.fetch
; dependencies to@types\whatwg-fetch
will cause conflicting declaration errors and will need to be removed. -
Standard library now has declarations for
ServiceWorker
; dependencies on@types\service_worker_api
will cause conflicting declaration errors and will need to be removed.
For full list of breaking changes see the breaking change issues.
In ES2015, constructors which return an object implicitly substitute the value of this
for any callers of super(...)
.
As a result, it is necessary to capture any potential return value of super(...)
and replace it with this
.
Example
A class C
as:
class C extends B {
public a: number;
constructor() {
super();
this.a = 0;
}
}
Will generate code as:
var C = (function (_super) {
__extends(C, _super);
function C() {
var _this = _super.call(this) || this;
_this.a = 0;
return _this;
}
return C;
}(B));
Notice:
_super.call(this)
is captured into a local variable_this
- All uses of
this
in the constructor body has been replaced by the result of thesuper
call (i.e._this
) - Each constructor now returns explicitly its
this
, to enable for correct inheritance
It is worth noting that the use of this
before super(...)
is already an error as of TypeScript 1.8
As part of substituting the value of this
with the value returned by a super(...)
call, subclassing Error
, Array
, and others may no longer work as expected.
This is due to the fact that constructor functions for Error
, Array
, and the like use ECMAScript 6's new.target
to adjust the prototype chain;
however, there is no way to ensure a value for new.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:
class FooError extends Error {
constructor(m: string) {
super(m);
}
sayHello() {
return "hello " + this.message;
}
}
you may find that:
- methods may be
undefined
on objects returned by constructing these subclasses, so callingsayHello
will result in an error. instanceof
will be broken between instances of the subclass and their instances, so(new FooError()) instanceof FooError
will returnfalse
.
Recommendation
As a recommendation, you can manually adjust the prototype immediately after any super(...)
calls.
class FooError extends Error {
constructor(m: string) {
super(m);
// Set the prototype explicitly.
Object.setPrototypeOf(this, FooError.prototype);
}
sayHello() {
return "hello " + this.message;
}
}
However, any subclass of FooError
will have to manually set the prototype as well.
For runtimes that don't support Object.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
onto this
), but the prototype chain itself cannot be fixed.
String, numeric, boolean and enum literal types are not inferred by default for const
declarations and readonly
properties. This means your variables/properties an have more narrowed type than before. This could manifest in using comparison operators such as ===
and !==
.
Example
const DEBUG = 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:
const DEBUG = <boolean>true; // type is `boolean`
String, numeric and boolean literal types will be inferred if the generic type parameter has a constraint of string
,number
or boolean
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
declare function push<T extends string>(...args: T[]): T;
var x = 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:
var x = push<string>("A", "B", "C"); // x is string
Previously the compiler silently gave the argument of the callback (c
below) a type any
. 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
declare function func(callback: () => void): any;
declare function func(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.
declare function func(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
let x = Math.pow((3, 5)); // x = NaN, was meant to be `Math.pow(3, 5)`
// This code does not do what it appears to!
let arr = [];
switch(arr.length) {
case 0, 1:
return 'zero or one';
default:
return 'more than one';
}
Recommendation
--allowUnreachableCode
will disable the warning for the whole compilation. Alternatively, you can use the void
operator to suppress the error for specific comma expressions:
let a = 0;
let y = (void a, 1); // no warning for `a`
- Node.firstChild, Node.lastChild, Node.nextSibling, Node.previousSibling, Node.parentElement and Node.parentNode are now
Node | null
instead ofNode
.
See #11113 for more details.
Recommendation is to explicitly check for null
or use the !
assertion operator (e.g. node.lastChild!
).
For full list of breaking changes see the breaking change issues.
Type narrowing does not cross function and class expressions, as well as lambda expressions.
Example
var x: number | string;
if (typeof x === "number") {
function inner(): number {
return x; // Error, type of x is not narrowed, c is number | string
}
var y: number = x; // OK, x is number
}
In the previous pattern the compiler can not tell when the callback will execute. Consider:
var x: number | string = "a";
if (typeof x === "string") {
setTimeout(() => console.log(x.charAt(0)), 0);
}
x = 5;
It is wrong to assume x
is a string
when x.charAt()
is called, as indeed it isn't.
Recommendation
Use constants instead:
const x: number | string = "a";
if (typeof x === "string") {
setTimeout(() => console.log(x.charAt(0)), 0);
}
Example
function g<T>(obj: T) {
var t: T;
if (obj instanceof RegExp) {
t = obj; // RegExp is not assignable to T
}
}
Recommendation Either declare your locals to be a specific type and not the generic type parameter, or use a type assertion.
Example
class C {
get x() { return 0; }
}
var c = new C();
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 ) {
function foo() {}
}
export = foo;
Recommendation
Use function expressions instead:
if( true ) {
const foo = function() {}
}
ES2015 tagged templates always pass their tag an immutable array-like object that has a property called raw
(which is also immutable).
TypeScript names this object the TemplateStringsArray
.
Conveniently, TemplateStringsArray
was assignable to an Array<string>
, so it's possible users took advantage of this to use a shorter type for their tag parameters:
function myTemplateTag(strs: string[]) {
// ...
}
However, in TypeScript 2.0, the language now supports the readonly
modifier and can express that these objects are immutable.
As a result, TemplateStringsArray
has also been made immutable, and is no longer assignable to string[]
.
Recommendation
Use TemplateStringsArray
explicitly (or use ReadonlyArray<string>
).
For full list of breaking changes see the breaking 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 to NaN
, will now loudly fail. You can reference the MDN 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.
const localPromise = Promise;
export { localPromise as Promise };
In TypeScript 1.8 we've added a set of reachability checks to prevent certain categories of errors. Specifically
-
check if code is reachable (enabled by default, can be disabled via
allowUnreachableCode
compiler option)function test1() { return 1; return 2; // error here } function test2(x) { if (x) { return 1; } else { throw new Error("NYI") } var y = 1; // error here }
-
check if label is unused (enabled by default, can be disabled via
allowUnusedLabels
compiler option)l: // error will be reported - label `l` is unused while (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
noImplicitReturns
compiler option)// error will be reported since function does not return anything explicitly when `x` is falsy. function test(x): number { if (x) return 10; }
-
check if control flow falls through cases in switch statement (disabled by default, can be enabled via
noFallthroughCasesInSwitch
compiler option). Note that cases without statements are not reported.switch(x) { // OK case 1: case 2: return 1; } switch(x) { case 1: if (y) return 1; case 2: return 2; }
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 empty out
file and no error.
- ImageData.data is now of type
Uint8ClampedArray
instead ofnumber[]
. See #949 for more details. - HTMLSelectElement .options is now of type
HTMLCollection
instead ofHTMLSelectElement
. See #1558 for more details. - HTMLTableElement.createCaption, HTMLTableElement.createTBody, HTMLTableElement.createTFoot, HTMLTableElement.createTHead, HTMLTableElement.insertRow, HTMLTableSectionElement.insertRow, and HTMLTableElement.insertRow now return
HTMLTableRowElement
instead ofHTMLElement
. See #3583 for more details. - HTMLTableRowElement.insertCell now return
HTMLTableCellElement
instead ofHTMLElement
. See #3583 for more details. - IDBObjectStore.createIndex and IDBDatabase.createIndex second argument is now of type
IDBObjectStoreParameters
instead ofany
. See #5932 for more details. - DataTransferItemList.Item returns type now is
DataTransferItem
instead ofFile
. See #6106 for more details. - Window.open return type now is
Window
instead ofany
. See #6418 for more details. - WeakMap.clear as removed. See #6500 for more details.
ES6 disallows accessing this
in a constructor declaration.
For example:
class B {
constructor(that?: any) {}
}
class C extends B {
constructor() {
super(this); // error;
}
}
class D extends B {
private _prop1: number;
constructor() {
this._prop1 = 10; // error
super();
}
}
For full list of breaking changes see the breaking change issues.
In a class, the type of the value this
will be inferred to the this
type.
This means subsequent assignments from values the original type can fail.
Example:
class Fighter {
/** @returns the winner of the fight. */
fight(opponent: Fighter) {
let theVeryBest = this;
if (Math.rand() < 0.5) {
theVeryBest = opponent; // error
}
return theVeryBest
}
}
Recommendations:
Add a type annotation:
class Fighter {
/** @returns the winner of the fight. */
fight(opponent: Fighter) {
let theVeryBest: Fighter = this;
if (Math.rand() < 0.5) {
theVeryBest = opponent; // no error
}
return theVeryBest
}
}
The keywords abstract, public, protected
and private
are FutureReservedWords 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 extends C
in the following example, and instead declares a concrete method m
and an additional property named abstract
.
Note that async
and declare
already correctly did ASI.
Example:
abstract class C {
abstract m(): number;
}
abstract class D extends C {
abstract
m(): 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 the breaking 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:
var x: { foo: number };
x = { foo: 1, baz: 2 }; // Error, excess property `baz`
var y: { 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:
var x: { 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.
let animalList: (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:
interface Foo {
foo: number;
}
interface FooBar {
foo: number;
bar: number;
}
var y: Foo;
y = <FooBar>{ foo: 1, bar: 2 };
Previously, for the files one.ts
and two.ts
, an import of "one"
in two.ts
would resolve to one.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 appropriate node_modules
folder as would be resolved by runtimes such as Node.js. For details, see the issue that describes the resolution algorithm.
Example:
./one.ts
export function f() {
return 10;
}
./two.ts
import { f as g } from "one";
Recommendations:
Fix any non-relative import names that were unintended (strongly suggested).
./one.ts
export function f() {
return 10;
}
./two.ts
import { f as g } from "./one";
Set the --moduleResolution
compiler option to classic
.
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,
export default function foo() {
}
namespace foo {
var x = 100;
}
and
export default class Foo {
a: number;
}
interface Foo {
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:
export default class Foo {
}
namespace Foo {
}
Recommendations:
Declare a local for your default export and use a separate export default
statement as so:
class Foo {
a: number;
}
interface foo {
b: string;
}
export default Foo;
For more details see the originating issue.
In accordance with the 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 of arguments
and eval
as variable or parameter names, use of future reserved words as variables or parameters, use of octal numeric literals, etc..
- MessageEvent and ProgressEvent constructors now expect arguments; see issue #4295 for more details.
- ImageData constructor now expects arguments; see issue #4220 for more details.
- File constructor now expects arguments; see issue #3999 for more details.
The compiler uses the new 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 to v0.17.1 or higher.
Entry point of TypeScript npm package was moved from bin
to lib
to unblock scenarios when 'node_modules/typescript/bin/typescript.js' is served from IIS (by default bin
is in the list of hidden segments so IIS will block access to this folder).
TypeScript 1.6 removes the preferGlobal
flag from package.json. If you rely on this behaviour please use npm 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 the breaking 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 per ES6 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:
function f() {
return () => arguments; // Error: The 'arguments' object cannot be referenced in an arrow function.
}
Recommendations:
// 1. Use named rest args
function f() {
return (...args) => { args; }
}
// 2. Use function expressions instead
function f() {
return function(){ arguments; }
}
For regular enums, pre 1.5, the compiler only 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:
var x = E.a; // previously inlined as "var x = 1; /*E.a*/"
enum E {
a = 1
}
Recommendation:
Add the const
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 are required to make an expression parse.
In the examples below, m
will have a contextual type, where previously it did not.
var x: SomeType = (n) => ((m) => q);
var y: SomeType = t ? (m => m.length) : undefined;
class C extends CBase<string> {
constructor() {
super({
method(m) { return m.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 the last released version before this change (TypeScript 1.5-alpha).
Here is a list of changes:
- Property
selection
is removed from typeDocument
- Property
clipboardData
is removed from typeWindow
- Removed interface
MSEventAttachmentTarget
- Properties
onresize
,disabled
,uniqueID
,removeNode
,fireEvent
,currentStyle
,runtimeStyle
are removed from typeHTMLElement
- Property
url
is removed from typeEvent
- Properties
execScript
,navigate
,item
are removed from typeWindow
- Properties
documentMode
,parentWindow
,createEventObject
are removed from typeDocument
- Property
parentWindow
is removed from typeHTMLDocument
- Property
setCapture
does not exist anywhere now - Property
releaseCapture
does not exist anywhere now - Properties
setAttribute
,styleFloat
,pixelLeft
are removed from typeCSSStyleDeclaration
- Property
selectorText
is removed from typeCSSRule
CSSStyleSheet.rules
is of typeCSSRuleList
instead ofMSCSSRuleList
documentElement
is of typeElement
instead ofHTMLElement
Event
has a new required propertyreturnValue
Node
has a new required propertybaseURI
Element
has a new required propertyclassList
Location
has a new required propertyorigin
- Properties
MSPOINTER_TYPE_MOUSE
,MSPOINTER_TYPE_TOUCH
are removed from typeMSPointerEvent
CSSStyleRule
has a new required propertyreadonly
- Property
execUnsafeLocalFunction
is removed from typeMSApp
- Global method
toStaticHTML
is removed HTMLCanvasElement.getContext
now returnsCanvasRenderingContext2D | WebGLRenderingContex
- Removed extension types
Dataview
,Weakmap
,Map
,Set
XMLHttpRequest.send
has two overloadssend(data?: Document): void;
andsend(data?: String): void;
window.orientation
is of typestring
instead ofnumber
- IE-specific
attachEvent
anddetachEvent
are removed fromWindow
Here is a list of libraries that are partly or entirely replaced by the added DOM types:
DefinitelyTyped/auth0/auth0.d.ts
DefinitelyTyped/gamepad/gamepad.d.ts
DefinitelyTyped/interactjs/interact.d.ts
DefinitelyTyped/webaudioapi/waa.d.ts
DefinitelyTyped/webcrypto/WebCrypto.d.ts
For more details, please see the full change.
In accordance with the 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 of arguments
and eval
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 the breaking change issues.
See issue #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.
var a: { x: number; y?: number };
var b: { x: number; z?: number };
// was { x: number; z?: number; }[]
// now { x: number; y?: number; }[]
var bs = [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 with any
).
Recommendation Provide a type annotation if you need a specific type to be chosen
var bs: { 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:
declare function foo<T>(x: T, y:T): T;
var r = foo(1, ""); // r used to be {}, now this is an error
With constraints:
interface Animal { x }
interface Giraffe extends Animal { y }
interface Elephant extends Animal { z }
function f<T extends Animal>(x: T, y: T): T { return undefined; }
var g: Giraffe;
var e: Elephant;
f(g, e);
See microsoft/TypeScript#824 (comment) for explanation.
Recommendations Specify an explicit type parameter if the mismatch was intentional:
var r = foo<{}>(1, ""); // Emulates 1.0 behavior
var r = foo<string|number>(1, ""); // Most useful
var r = foo<any>(1, ""); // Easiest
f<Animal>(g, e);
or rewrite the function definition to specify that mismatches are OK:
declare function foo<T,U>(x: T, y:U): T|U;
function f<T extends Animal, U extends Animal>(x: T, y: U): T|U { return undefined; }
You cannot use heterogeneous argument types anymore:
function makeArray<T>(...items: T[]): T[] { return items; }
var r = makeArray(1, ""); // used to return {}[], now an error
Likewise for new Array(...)
Recommendations Declare a back-compatible signature if the 1.0 behavior was desired:
function makeArray<T>(...items: T[]): T[];
function makeArray(...items: {}[]): {}[];
function makeArray<T>(...items: T[]): T[] { return items; }
var f10: <T>(x: T, b: () => (a: T) => void, y: T) => T;
var r9 = f10('', () => (a => a.foo), 1); // r9 was any, now this is an error
Recommendations Manually specify a type parameter
var r9 = f10<any>('', () => (a => a.foo), 1);
ECMAScript 2015 Language Specification (ECMA-262 6th Edition) specifies that ClassDeclaration and ClassExpression are strict mode productions. Thus, additional restrictions will be applied when parsing a class declaration or class expression.
Examples:
class implements {} // Invalid: implements is a reserved word in strict mode
class C {
foo(arguments: any) { // Invalid: "arguments" is not allow as a function argument
var eval = 10; // Invalid: "eval" is not allowed as the left-hand-side expression
arguments = []; // 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 the breaking change issues.
Examples:
var ResultIsNumber17 = +(null + undefined);
// Operator '+' cannot be applied to types 'undefined' and 'undefined'.
var ResultIsNumber18 = +(null + null);
// Operator '+' cannot be applied to types 'null' and 'null'.
var ResultIsNumber19 = +(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();