You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
One of the big things we've wanted to do with the type system.
A little bit of work left on the PR itself.
New compiler switch.
--strictNullChecks.
Introduces two new (accessible) types called null and undefined.
Writing T? is the same as writing T | null | undefined.
Non-immediate assignments
JS problem: all variables, by default, have the value undefined:
varx: number;// ...x=1;
That's still valid!
For that reason, we do some basic assignment-before-use checking.
"Rudimentary" at this point.
"Perfect" support would require full data-flow analysis.
Function hoisting makes this hard.
Even Flow doesn't do full data-flow analysis.
Though they do control-flow and "type"-flow analysis.
function(x: string|number){if(typeofx==="string"){x=+x;}// Type of 'x' here is 'number'.}
Hasn't been a problem so far, but it might start to be a problem for us?
Type-flow analysis is in some sense a very general form of data-flow analysis, so...
We're going to keep it in mind, but it's not clear what kind of performance implications it would have.
Type guards
Standard checks become type guards.
// Compiled with --strictNullChecksdeclarefunctionf(x: number): string;letx: number?;if(x){f(x);// Ok, type of x is number here}else{f(x);// Error, type of x is number? here}leta=x!=null ? f(x) : "";// Type of a is stringletb=x&&f(x);// Type of b is string?
x, x == null, x == undefined all have the same behavior.
x === undefined and x === null have differing respective behavior.
What happens for teams that strictly use null or undefined and use ===/!==?
We actually wouldn't be using optionals within the compiler because we only use undefined!
We would make a type Maybe<T> = T | undefined.
Maybe we should add that and type Nullable<T> = T | null to lib.d.ts.
Dotted names in type guards
interfaceOptions{location?: {x?: number;y?: number;};functionfoo(options?: Options){if(options&&options.location&&options.location.x){constx=options.location.x;// Type of x is number}}
Works on optionals.
Arrays
How do we deal with arrays and out-of-bounds?
These are simply places we cannot solve the problem.
The solution makes things insane to deal with.
The cure is worse than the disease.
Behavior of widening and contextual typing
Widening is no longer performed when using this new flag.
Users now just get the undefined or null types when using these types.
So they won't be able to read from them.
So they'll have to explicitly opt out.
Does that mean we don't need --noImplicitAny?
Almost!
Empty array literals are still an issue.
So --noImplicitAny forces you to decide what to do with empty arrays.
Why would they not just become undefined[]?
var a: number[] = [];
How does this interact with the plan to "contextually type" undefined/null?
We were saying this was necessary for contextually implementing class properties.
Probably shouldn't be impacted much by this.
Non-null assertion operator
A new ! postfix expression-level operator.
Produces no runtime-dependent code.
// Compiled with --strictNullChecksfunctionvalidateEntity(e: Entity?){// Throw exception if e is null or invalid entity}functionprocessEntity(e: Entity?){validateEntity(e);lets=e!.name;// Assert that e is non-null and access name}
Why can't a type predicate take care of that?
It could but it's just cumbersome for some scenarios.
Optionals
Optional properties and parameters have fairly intuitive behavior.
functionfoo(x?: number){}
That implicitly gives x the type number | undefined.
What about default parameters?
functionfoo(x=15){}
Externally, x is number | undefined.
Declaration files will reflect this.
Internally, x has type number.
It's as if you had implicitly done the checking you needed (e.g. if (x === undefined) { x = 15; }).
Same work has been done for destructuring defaults as well.
There's no best common type between undefined and number, so this caused an error.
This is a special case we need to start considering.
Enum member types may need this if we choose to adopt them.
Adoption issues
Non-null checks are an all-or-nothing sort of feature.
Tons of declaration files have been written without this feature in mind (because, well, they couldn't).
Becomes a game of wack-a-mole for consumers in patching up declaration files.
We could consider a file-specific understanding, or use a tri-state of nullability, but this actually becomes a mental burden for both users and ourselves.
Why does this get a switch but not readonly?
Meaningful work we can do with readonly that's backwards compatible.
Old code doesn't change semantics.
Nullability doesn't really have a good story for backwards compatibility - you're now changing the semantics of the old syntax.
The text was updated successfully, but these errors were encountered:
Non-nullable types (#7140)
--strictNullChecks
.null
andundefined
.T?
is the same as writingT | null | undefined
.Non-immediate assignments
JS problem: all variables, by default, have the value
undefined
:"Rudimentary" at this point.
"Perfect" support would require full data-flow analysis.
Even Flow doesn't do full data-flow analysis.
Though they do control-flow and "type"-flow analysis.
Hasn't been a problem so far, but it might start to be a problem for us?
Type-flow analysis is in some sense a very general form of data-flow analysis, so...
We're going to keep it in mind, but it's not clear what kind of performance implications it would have.
Type guards
Standard checks become type guards.
x
,x == null
,x == undefined
all have the same behavior.x === undefined
andx === null
have differing respective behavior.null
orundefined
and use===
/!==
?undefined
!type Maybe<T> = T | undefined
.type Nullable<T> = T | null
tolib.d.ts
.Dotted names in type guards
Arrays
Behavior of widening and contextual typing
undefined
ornull
types when using these types.--noImplicitAny
?--noImplicitAny
forces you to decide what to do with empty arrays.undefined[]
?var a: number[] = [];
undefined
/null
?Non-null assertion operator
A new
!
postfix expression-level operator.Produces no runtime-dependent code.
Optionals
Optional properties and parameters have fairly intuitive behavior.
x
the typenumber | undefined
.What about default parameters?
x
isnumber | undefined
.x
has typenumber
.if (x === undefined) { x = 15; }
).Best common type issues
undefined
andnumber
, so this caused an error.Adoption issues
readonly
?readonly
that's backwards compatible.The text was updated successfully, but these errors were encountered: