Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Non-nullable types#7140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
ahejlsberg merged 65 commits intomasterfromstrictNullChecks
Mar 21, 2016
Merged

Non-nullable types#7140

ahejlsberg merged 65 commits intomasterfromstrictNullChecks
Mar 21, 2016

Conversation

ahejlsberg
Copy link
Member

@ahejlsbergahejlsberg commentedFeb 18, 2016
edited
Loading

This PR implements support for null- and undefined-aware types and strict null checking that can be enabled with a new--strictNullChecks compiler 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 valuesnull andundefined respectively. Previously it was not possible to explicitly name these types, butnull andundefined may now be used as type names regardless of type checking mode.

The type checker previously considerednull andundefined assignable to anything. Effectively,null andundefined were valid values ofevery 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, thenull andundefined values arenot in the domain of every type and are only assignable to themselves andany (the one exception being thatundefined is also assignable tovoid). So, whereasT andT | undefined are considered synonymous in regular type checking mode (becauseundefined is considered a subtype of anyT), they are different types in strict type checking mode, and onlyT | undefined permitsundefined values. The same is true for the relationship ofT toT | null.

// Compiled with --strictNullChecksletx:number;lety:number|undefined;letz:number|null|undefined;x=1;// Oky=1;// Okz=1;// Okx=undefined;// Errory=undefined;// Okz=undefined;// Okx=null;// Errory=null;// Errorz=null;// Okx=y;// Errorx=z;// Errory=x;// Oky=z;// Errorz=x;// Okz=y;// Ok

Assigned-before-use checking

In strict null checking mode the compiler requires every reference to a local variable of a type that doesn't includeundefined to be preceded by an assignment to that variable in every possible preceding code path.

For example:

// Compiled with --strictNullChecksletx:number;lety:number|null;letz:number|undefined;x;// Error, reference not preceded by assignmenty;// Error, reference not preceded by assignmentz;// Okx=1;y=null;x;// Oky;// Ok

The compiler checks that variables are definitely assigned by performingcontrol flow based type analysis. For further details on this topic, see#8010.

Optional parameters and properties

Optional parameters and properties automatically haveundefined added to their types, even when their type annotations don't specifically includeundefined. For example, the following two types are identical:

// Compiled with --strictNullCheckstypeT1=(x?:number)=>string;// x has type number | undefinedtypeT2=(x?:number|undefined)=>string;// x has type number | undefined

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 includesnull orundefined. However, type guards are extended to support non-null and non-undefined checks. For example:

// Compiled with --strictNullChecksdeclarefunctionf(x:number):string;letx:number|null|undefined;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?

Non-null and non-undefined type guards may use the==,!=,===, or!== operator to compare tonull orundefined, as inx != null orx === 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:

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}}

Type guards for dotted names also work with user defined type guard functions and thetypeof andinstanceof operators and do not depend on the--strictNullChecks compiler 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 forx.y.z will have no effect following an assignment tox,x.y, orx.y.z.

Expression operators

Expression operators permit operand types to includenull and/orundefined but always produce values of non-null and non-undefined types.

// Compiled with --strictNullChecksfunctionsum(a:number|null,b:number|null){returna+b;// Produces value of type number}

The&& operator addsnull and/orundefined to the type of the right operand depending on which are present in the type of the left operand, and the|| operator removes bothnull andundefined from the type of the left operand in the resulting union type.

// Compiled with --strictNullChecksinterfaceEntity{name:string;}letx:Entity|null;lets=x&&x.name;// s is of type string | nulllety=x||{name:"test"};// y is of type Entity

Type widening

Thenull andundefined types arenot widened toany in strict null checking mode.

letz=null;// Type of z is null

In regular type checking mode the inferred type ofz isany because of widening, but in strict null checking mode the inferred type ofz isnull (and therefore, absent a type annotation,null is 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 ofx withnull andundefined excluded. Similar to type assertions of the forms<T>x andx as T, the! non-null assertion operator is simply removed in the emitted JavaScript 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}

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, thenull andundefined types 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.

dallonf, weswigham, mquandalle, wwwillchen, johnfn, falsandtru, niieani, milutinovici, emilgpa, svieira, and 220 more reacted with thumbs up emojiahmetabdi, cies, hristozov, egeozcan, RobertoUa, HerringtonDarkholme, kenhahn85, GoToLoop, keesey, lowdewijk, and 13 more reacted with laugh emojicybrown, mquandalle, johnfn, jods4, sergey-shandar, svieira, ziahamza, supershabam, PatrickJS, fitzgen, and 94 more reacted with hooray emojiEyas, sergey-shandar, emilgpa, ziahamza, thorn0, guncha, PatrickJS, passy, ulrichb, aymericbeaumet, and 82 more reacted with heart emoji
Conflicts:src/compiler/checker.tssrc/compiler/types.ts
@RyanCavanaugh
Copy link
Member

This compiles without error under--strictnullchecks

letx:string;x.substr(10);

while the equivalent

letx:string=undefined;x.substr(10);

does not

@ahejlsberg
Copy link
MemberAuthor

@RyanCavanaugh Yup, that's the definite assignment analysis work item I've got listed in the remaining work section.

@robertknight
Copy link

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.

mquandalle, radev, Xesued, passy, aymericbeaumet, EvansThomas, brendanzab, jin, lievenlemiengre, k0nserv, and 21 more reacted with thumbs up emoji

@myitcv
Copy link

👍 to this work

type guards are extended to support non-null checks.

Can I confirm the following is also a valid type guard onx?

// Compiled with --strictNullChecksinterfaceEntity{name:string;}letx: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 --strictNullChecksfunctionsum(a:number?,b:number?,c:number,d:number){console.log(a+b);// errorconsole.log(a+c);// errorconsole.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?

@tejacques
Copy link

👍 very nice to see this!

There was some discussion in other issues about theif(x) style typeguards WRT falsy values.

For example:

letx:number?=0;lety:string?='';letz:boolean?=false;

In particular,boolean? guarding withif(z) feels pretty bad, sincefalse is one of the two legitimate values. The other are unfortunate but not terrible.

It would be nice to have a guard work onx != null to get around this issue.

@ahejlsberg
Copy link
MemberAuthor

@myitcv Yes,x != undefined will work as a non-null guard(right now it only works withx != null but I will fix that).

The rationale for the expression operators is that they actually have well defined semantics for thenull andundefined 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 Anx != null type guard already works.

rajington added a commit to rajington/flow-vs-typescript that referenced this pull requestJun 4, 2016
Despite being a fan of Flow, I do think it's prudent for any recent comparison to include SOME features on the project timeline, including [non-nullable types](microsoft/TypeScript#7140) in version 2.
@microsoftmicrosoft locked and limited conversation to collaboratorsJun 19, 2018
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.
Reviewers
No reviews
Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
TypeScript 2.0
Development

Successfully merging this pull request may close these issues.

27 participants
@ahejlsberg@RyanCavanaugh@robertknight@myitcv@tejacques@zpdDG4gta8XKpMCd@JsonFreeman@ivogabe@jeffreymorlan@samwgoldman@basarat@Arnavion@Igorbek@IanYates@DanielRosenwasser@danquirk@CyrusNajmabadi@tinganho@dallonf@spion@mhegazy@jods4@malibuzios@Raynos@electricessence@emilgpa@msftclas

[8]ページ先頭

©2009-2025 Movatter.jp