Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upNon-nullable types #7140
Conversation
ahejlsberg
added some commits
Feb 15, 2016
msftclas
added
the
cla-not-required
label
Feb 18, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
RyanCavanaugh
Feb 19, 2016
Member
This compiles without error under --strictnullchecks
let x: string;
x.substr(10);while the equivalent
let x: string = undefined;
x.substr(10);does not
|
This compiles without error under let x: string;
x.substr(10);while the equivalent let x: string = undefined;
x.substr(10);does not |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ahejlsberg
Feb 19, 2016
Member
@RyanCavanaugh Yup, that's the definite assignment analysis work item I've got listed in the remaining work section.
|
@RyanCavanaugh Yup, that's the definite assignment analysis work item I've got listed in the remaining work section. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
robertknight
Feb 19, 2016
Note: We use postfix notation for the ? operator to avoid ambiguities in types
like string?[] and string[]?. We may consider also supporting prefix notation similar to
the Flow type checker.
If Flow and TypeScript can agree on syntax for this and thereby enable code to be parsed with either TypeScript or Babel that would be very helpful for projects wishing to try one or the other.
robertknight
commented
Feb 19, 2016
If Flow and TypeScript can agree on syntax for this and thereby enable code to be parsed with either TypeScript or Babel that would be very helpful for projects wishing to try one or the other. |
ahejlsberg
added some commits
Feb 19, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
myitcv
Feb 19, 2016
type guards are extended to support non-null checks.
Can I confirm the following is also a valid type guard on x?
// Compiled with --strictNullChecks
interface Entity {
name: string;
}
let x: Entity?;
if (x != undefined) {
// x is of type Entity
// guaranteed runtime safe use of x
}Expression operators permit the operands to be both nullable and non-nullable and always produce values of non-nullable types.
Please can you explain the rationale behind this?
I would have thought the following a more intuitive interpretation:
// Compiled with --strictNullChecks
function sum(a: number?, b: number?, c: number, d: number) {
console.log(a + b); // error
console.log(a + c); // error
console.log(c + d); // OK
}A new
!postfix expression operator may be used to assert that its operand is non-nullable in contexts where the type checker is unable to conclude that fact.
Given the support you describe with type guards, can you explain why this is operator is necessary?
myitcv
commented
Feb 19, 2016
Can I confirm the following is also a valid type guard on // Compiled with --strictNullChecks
interface Entity {
name: string;
}
let x: Entity?;
if (x != undefined) {
// x is of type Entity
// guaranteed runtime safe use of x
}
Please can you explain the rationale behind this? I would have thought the following a more intuitive interpretation: // Compiled with --strictNullChecks
function sum(a: number?, b: number?, c: number, d: number) {
console.log(a + b); // error
console.log(a + c); // error
console.log(c + d); // OK
}
Given the support you describe with type guards, can you explain why this is operator is necessary? |
This was referenced Feb 19, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
tejacques
Feb 19, 2016
There was some discussion in other issues about the if(x) style typeguards WRT falsy values.
For example:
let x: number? = 0;
let y: string? = '';
let z: boolean? = false;In particular, boolean? guarding with if(z) feels pretty bad, since false is one of the two legitimate values. The other are unfortunate but not terrible.
It would be nice to have a guard work on x != null to get around this issue.
tejacques
commented
Feb 19, 2016
|
There was some discussion in other issues about the For example: let x: number? = 0;
let y: string? = '';
let z: boolean? = false;In particular, It would be nice to have a guard work on |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ahejlsberg
Feb 19, 2016
Member
@myitcv Yes, x != undefined will work as a non-null guard (right now it only works with .x != null but I will fix that)
The rationale for the expression operators is that they actually have well defined semantics for the null and undefined values. Certainly we want to support nullable values for the comparison operators, but I can see being more restrictive for the arithmetic operators. Still, not sure it merits the extra complexity.
The postfix ! assertion operator is useful in cases where the type checker can't conclude that a value is non-null but you know it to be true because of program logic. My description of the PR above gives an example of such a case.
@tejacques An x != null type guard already works.
|
@myitcv Yes, The rationale for the expression operators is that they actually have well defined semantics for the The postfix @tejacques An |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
tejacques
Feb 19, 2016
Ah yes I see the commit now -- thanks @ahejlsberg! Very excited about this and I'll be testing it out extensively over the weekend.
tejacques
commented
Feb 19, 2016
|
Ah yes I see the commit now -- thanks @ahejlsberg! Very excited about this and I'll be testing it out extensively over the weekend. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
aleksey-bykov
Feb 20, 2016
Is this feature just a sugared view on a | void that has been used meanwhile?
aleksey-bykov
commented
Feb 20, 2016
|
Is this feature just a sugared view on |
ahejlsberg
added some commits
Feb 20, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
JsonFreeman
Feb 20, 2016
Contributor
Somewhat related to @myitcv's question, do ProperyAccess and ElementAccess expressions permit their left operand types to be nullable? I couldn't find an error for this in the review, but figured it is likely disallowed by virtue of the union type representation.
Also, I just want to say this looks awesome!
|
Somewhat related to @myitcv's question, do ProperyAccess and ElementAccess expressions permit their left operand types to be nullable? I couldn't find an error for this in the review, but figured it is likely disallowed by virtue of the union type representation. Also, I just want to say this looks awesome! |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ahejlsberg
Feb 20, 2016
Member
@JsonFreeman (Hi, Jason!) Property and element accesses are disallowed when the left operand is nullable (as you say, because of the union type representation).
|
@JsonFreeman (Hi, Jason!) Property and element accesses are disallowed when the left operand is nullable (as you say, because of the union type representation). |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
JsonFreeman
Feb 20, 2016
Contributor
Thanks Anders! I'm happy to see this feature come together so well - I think it's a big step for the language :)
|
Thanks Anders! I'm happy to see this feature come together so well - I think it's a big step for the language :) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ivogabe
Feb 20, 2016
Contributor
- Definite assignment analysis for non-nullable variables and properties in classes.
@ahejlsberg I think #6959 can be used for this (if it will be merged), as my PR can already narrow types based on assignments:
let x: string | number;
x = 42;
// x: numberThat can also be used to narrow T? to T. In general, I think that those two features would be a nice addition to each other.
@ahejlsberg I think #6959 can be used for this (if it will be merged), as my PR can already narrow types based on assignments: let x: string | number;
x = 42;
// x: numberThat can also be used to narrow |
saneyuki
referenced this pull request
Feb 22, 2016
Open
API stabilize: Option<T>.isSome should be getter (accessor property) vs getter function (data property) #93
ahejlsberg
added this to the TypeScript 2.0 milestone
Apr 25, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
electricessence
commented
Apr 26, 2016
|
Wow. Basically code contracts built in!!! LOVE YOU GUYS!!! |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
emilgpa
Apr 30, 2016
The following code (only with strictNullChecks enabled) raises error:
var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (var [key, value] of myMap) {
alert(key + " = " + value);
}It is a bug?
emilgpa
commented
Apr 30, 2016
•
|
The following code (only with var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (var [key, value] of myMap) {
alert(key + " = " + value);
}It is a bug? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ahejlsberg
Apr 30, 2016
Member
@DasHaus That looks like a bug. BTW, it only repros with --strictNullChecks and --target es6.
|
@DasHaus That looks like a bug. BTW, it only repros with |
ahejlsberg commentedFeb 18, 2016
•
edited
Edited 1 time
-
ahejlsberg
edited May 22, 2016 (most recent)
This PR implements support for null- and undefined-aware types and strict null checking that can be enabled with a new
--strictNullCheckscompiler switch. For context on this topic, see discussion in #185.Null- and undefined-aware types
TypeScript has two special types, Null and Undefined, that have the values
nullandundefinedrespectively. Previously it was not possible to explicitly name these types, butnullandundefinedmay now be used as type names regardless of type checking mode.The type checker previously considered
nullandundefinedassignable to anything. Effectively,nullandundefinedwere valid values of every type and it wasn't possible to specifically exclude them (and therefore not possible to detect erroneous use of them). This changes in the new strict null checking mode.In strict null checking mode, the
nullandundefinedvalues are not in the domain of every type and are only assignable to themselves andany(the one exception being thatundefinedis also assignable tovoid). So, whereasTandT | undefinedare considered synonymous in regular type checking mode (becauseundefinedis considered a subtype of anyT), they are different types in strict type checking mode, and onlyT | undefinedpermitsundefinedvalues. The same is true for the relationship ofTtoT | null.Assigned-before-use checking
In strict null checking mode the compiler requires every reference to a local variable of a type that doesn't include
undefinedto be preceded by an assignment to that variable in every possible preceding code path.For example:
The compiler checks that variables are definitely assigned by performing control flow based type analysis. For further details on this topic, see #8010.
Optional parameters and properties
Optional parameters and properties automatically have
undefinedadded to their types, even when their type annotations don't specifically includeundefined. For example, the following two types are identical:Non-null and non-undefined type guards
A property access or a function call produces a compile-time error if the object or function is of a type that includes
nullorundefined. However, type guards are extended to support non-null and non-undefined checks. For example:Non-null and non-undefined type guards may use the
==,!=,===, or!==operator to compare tonullorundefined, as inx != nullorx === undefined. The effects on subject variable types accurately reflect JavaScript semantics (e.g. double-equals operators check for both values no matter which one is specified whereas triple-equals only checks for the specified value).Dotted names in type guards
Type guards previously only supported checking local variables and parameters. Type guards now support checking "dotted names" consisting of a variable or parameter name followed one or more property accesses. For example:
Type guards for dotted names also work with user defined type guard functions and the
typeofandinstanceofoperators and do not depend on the--strictNullCheckscompiler option.A type guard for a dotted name has no effect following an assignment to any part of the dotted name. For example, a type guard for
x.y.zwill have no effect following an assignment tox,x.y, orx.y.z.Expression operators
Expression operators permit operand types to include
nulland/orundefinedbut always produce values of non-null and non-undefined types.The
&&operator addsnulland/orundefinedto the type of the right operand depending on which are present in the type of the left operand, and the||operator removes bothnullandundefinedfrom the type of the left operand in the resulting union type.Type widening
The
nullandundefinedtypes are not widened toanyin strict null checking mode.In regular type checking mode the inferred type of
zisanybecause of widening, but in strict null checking mode the inferred type ofzisnull(and therefore, absent a type annotation,nullis the only possible value forz).Non-null assertion operator
A new
!postfix expression operator may be used to assert that its operand is non-null and non-undefined in contexts where the type checker is unable to conclude that fact. Specifically, the operationx!produces a value of the type ofxwithnullandundefinedexcluded. Similar to type assertions of the forms<T>xandx as T, the!non-null assertion operator is simply removed in the emitted JavaScript code.Compatibility
The new features are designed such that they can be used in both strict null checking mode and regular type checking mode. In particular, the
nullandundefinedtypes are automatically erased from union types in regular type checking mode (because they are subtypes of all other types), and the!non-null assertion expression operator is permitted but has no effect in regular type checking mode. Thus, declaration files that are updated to use null- and undefined-aware types can still be used in regular type checking mode for backwards compatiblity.In practical terms, strict null checking mode requires that all files in a compilation are null- and undefined-aware.
We are contemplating a pragma of some form that can be added to declaration files such that the compiler can verify that all referenced declaration files are null- and undefined-aware in a compilation that uses strict null checking.