GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Add support for Optional Chaining by rbuckton · Pull Request #33294 · microsoft/TypeScript

Conversation

@rbuckton

@rbuckton Ron Buckton (rbuckton) commented Sep 7, 2019 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

This PR adds support for the ECMAScript Optional Chaining proposal which is now at stage 3.

Optional Expressions

An optional expression is an expression involving a property access, element access, or call, in which the expression is guarded against null and undefined through the use of the ?. token:

a?.b // optional property access
a?.[x] // optional element access
a?.() // optional call

In these cases, when a is either null or undefined, the result of the expression becomes undefined. When this happens, any side effects to the right of the ?. operator are not evaluated.

When emit down-level, the above expressions are translated into the following JavaScript:

var _a, _b, _c;
(_a = a) === null || _a === void 0 ? void 0 : _a.b; // optional property access 'a?.b'
(_b = a) === null || _b === void 0 ? void 0 : _b[x]; // optional element access 'a?.[x]'
(_c = a) === null || _c === void 0 ? void 0 : _c(); // optional call 'a?.()'

Optional Chains

An optional chain is an optional expression followed by one or more subsequent regular property access, element access, or call argument lists:

a?.b.c; // property access chain
a?.b[x]; // element access chain
a?.b(); // call chain

When a is either null or undefined above, the rest of the chain is also not evaluated. However, if a is any other value, the expression is evaluated as normal. In the above cases, if a.b were either null or undefined, the expression would still throw as the ?. token only guards the value of a.

When emit down-level, the above expressions are translated into the following JavaScript:

var _a, _b, _c;
(_a = a) === null || _a === void 0 ? void 0 : _a.b.c; // property access chain 'a?.b.c'
(_b = a) === null || _b === void 0 ? void 0 : _b.b[x]; // element access chain 'a?.b[x]'
(_c = a) === null || _c === void 0 ? void 0 : _c.b(); // call chain `a?.b()`

Optional Chaining and Generics

In addition to supporting ?.( for an optional call, we also support supplying generic type arguments to an optional call:

a?.<string>(b)

Optional Chaining and the Type System

When running outside of strictNullChecks, optional chaining should have no observable effect on the type system, as null and undefined in most cases are removed or widened to any.

When running inside of strictNullChecks, optional chaining introduces a special internal optional marker type. The optional type is a special case of the undefined type, and is treated as undefined for most type checking operations. Whenever the type checker encounters an optional expression, the null and undefined types are removed from the type of the expression and the optional type is added in its place. In this way, an optional chain can detect whether its preceding expression's type introduced a null or undefined in any step of the chain to the right of the optional expression.

For example:

declare let a: { b: { c: number } | undefined } | undefined;
a?.b?.c; // ok: has type `number | undefined`
a?.b.c; // error: object is possibly undefined (at `a?.b`)

In the first case, the expression a?.b?.c is safe to evaluate as both the a variable and the b property are guarded. In the second case, we can determine that it is not safe to evaluate the c property on a?.b as the b property is possibly undefined.

Fixes #16

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

j-oliveras, mariusschulz, amarantedaniel, SimenB, satya164, esamattis, norato, gespispace, jwbay, gengjiawen, and 232 more reacted with thumbs up emoji SamChou19815, alitaheri, j-oliveras, mariusschulz, amarantedaniel, satya164, norato, jwbay, xiel, prog, and 129 more reacted with hooray emoji j-oliveras, mariusschulz, karlhorky, matepapp, amarantedaniel, satya164, xiel, alitaheri, norato, soneymathew, and 107 more reacted with heart emoji alitaheri, j-oliveras, mariusschulz, amarantedaniel, satya164, norato, jwbay, cevek, Mathitos, mikaello, and 59 more reacted with rocket emoji garkin, williamluke4, litvancom, TJReinert, jackkoppa, itsMapleLeaf, a1russell, gisenberg, ericbf, wojciech-bilicki-oke, and 3 more reacted with eyes emoji
All reactions
  • 👍 242 reactions
  • 🎉 139 reactions
  • ❤️ 117 reactions
  • 🚀 69 reactions
  • 👀 13 reactions
@rbuckton
Add support for Optional Chaining
c95daab
@rbuckton
Ron Buckton (rbuckton) requested review from Anders Hejlsberg (ahejlsberg), Nathan Shively-Sanders (sandersn), Sheetal Nandi (sheetalkamat) and Wesley Wigham (weswigham) September 7, 2019 00:56
@mariusschulz

Marius Schulz (mariusschulz) commented Sep 7, 2019

Copy link
Copy Markdown
Contributor

I've been looking forward to Optional Chaining in TypeScript for a long time! Looking forward to seeing this PR land. :)

I'm curious, what was the reason that you decided to emit (_a = a) === null || _a === void 0 instead of the shorter (_a = a) == null?

var _a, _b, _c;
(_a = a) == null ? void 0 : _a.b; // optional property access 'a?.b'
(_b = a) == null ? void 0 : _b[x]; // optional element access 'a?.[x]'
(_c = a) == null ? void 0 : _c(); // optional call 'a?.()'
satya164, MarenkovIgor, SpencerPark, nanot1m, hasparus, akesfeden, ckknight, brandonburrus, bfricka, 0rvar, and 2 more reacted with thumbs up emoji millsp reacted with thumbs down emoji
All reactions
  • 👍 12 reactions
  • 👎 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@SimenB

Simen Bekkhus (SimenB) commented Sep 7, 2019

Copy link
Copy Markdown

This is super exciting 🎉 Any plans to surface a type error if the value is not either null or undefined? In which case it's unnecessary, so having that be an error would be sorta like TS2367, and we can avoid the runtime overhead

Harpush reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@jwbay

jwbay commented Sep 7, 2019

Copy link
Copy Markdown
Contributor

Marius Schulz (@mariusschulz) See #16 (comment)

mariusschulz, ExE-Boss, SpencerPark, and jcalz reacted with thumbs up emoji
All reactions
  • 👍 4 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@fbartho

Frederic Barthelemy (fbartho) commented Sep 7, 2019

Copy link
Copy Markdown

Simen Bekkhus (@SimenB) surfacing an error there would only help perfectly typed projects avoid runtime slowdowns, but it would also impose a syntax tax on projects that have to deal with the real world — infinite node_modules that are only partially typed, or where the types aren’t accurate. I wouldn’t want to have to cast (improperlyTyped as any)?.foo?.bar As this kind of would defeat some of the value of this operator.

I’d support a flag defaulting to off, --strictOptionalChaining, however!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@rbuckton

Ron Buckton (rbuckton) commented Sep 7, 2019

Copy link
Copy Markdown
Contributor Author

Any plans to surface a type error if the value is not either null or undefined?

Not at this time, no. Such an error would only be valid under strict mode (since ?. has no effect on types in non-strict mode), and would prevent you from writing defensive code against external APIs that are possibly unsafe. Also, we do not currently do this for the non-null assertion operator (!), so it would not make sense for us to do that here as well.

That kind of rule may be better implemented as a lint rule rather than a TypeScript-specific flag.

dsherret, treybrisbane, mariusschulz, alitaheri, ExE-Boss, DomiR, and tomblachut reacted with thumbs up emoji
All reactions
  • 👍 7 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@rbuckton
Add grammar error for invalid tagged template, more tests
c2f53fc
@orta Orta Therox (orta) mentioned this pull request Sep 9, 2019
TypeScript Roadmap: July - December 2019 #33118
Closed
@ExE-Boss

ExE Boss (ExE-Boss) commented Sep 11, 2019

Copy link
Copy Markdown
Contributor

Actually,

a?.b // optional property access
a?.[x] // optional element access
a?.() // optional call

should get transpiled to:

var _a, _a2, _a3;

(_a = a) === null || _a === void 0 ? void 0 : _a.b; // optional property access
(_a2 = a) === null || _a2 === void 0 ? void 0 : _a2[x]; // optional element access
(_a3 = a) === null || _a3 === void 0 ? void 0 : _a3(); // optional call
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@rbuckton

Ron Buckton (rbuckton) commented Sep 11, 2019

Copy link
Copy Markdown
Contributor Author

ExE Boss (@ExE-Boss): How does your example differ from my example in the description?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ExE-Boss

ExE Boss (ExE-Boss) commented Sep 11, 2019 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Yours uses:

var _a, _b, _c; // Implies optional access from different variables `a`, `b` and `c`.

Whereas mine uses

var _a, _a2, _a3; // Implies distinct optional accesses from variable `a`.
ElianCordoba and arthurvasconcelos reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Jessidhia

Jessica Franco (Jessidhia) commented Sep 12, 2019 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

There is, in fact, a lint rule for that, though it will need to be updated for the ?. case. tslint / eslint

ExE-Boss reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@orta

Orta Therox (orta) commented Sep 23, 2019

Copy link
Copy Markdown
Contributor

TypeScript Bot (@typescript-bot) pack this

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Sep 23, 2019 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Heya Orta Therox (@orta), I've started to run the tarball bundle task on this PR at c2f53fc. You can monitor the build here. It should now contribute to this PR's status checks.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Sep 23, 2019

Copy link
Copy Markdown
Contributor

Hey Orta Therox (@orta), I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/45184/artifacts?artifactName=tgz&fileId=4C24B3EBE47F04661C6F0C3769DECEBF2B693C39E432217A9786260BDF23992502&fileName=/typescript-3.7.0-insiders.20190923.tgz"
    }
}

and then running npm install.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@orta

Orta Therox (orta) commented Sep 23, 2019

Copy link
Copy Markdown
Contributor

Here's a playground

mapf122, j-oliveras, jackkoppa, dragomirtitian, patoncrispy, washingtonsoares, and nisimjoseph reacted with thumbs up emoji PabloSzx, j-oliveras, jackkoppa, dragomirtitian, karlhorky, washingtonsoares, and nisimjoseph reacted with hooray emoji
All reactions
  • 👍 7 reactions
  • 🎉 7 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

weswigham
Wesley Wigham (weswigham) reviewed Sep 23, 2019
View reviewed changes
Comment thread src/compiler/types.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread tests/cases/conformance/expressions/optionalChaining/callChain/callChain.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread tests/cases/conformance/expressions/optionalChaining/taggedTemplateChain/taggedTemplateChain.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

weswigham
Wesley Wigham (weswigham) reviewed Sep 23, 2019
View reviewed changes

@weswigham Wesley Wigham (weswigham) left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to see some control flow tests - I'm pretty sure the control flow graph for

const q = Math.random() > 0.5 ? undefined : { b: 12 };
let b: number;
const a = q?.[b = 12, "b"];
b.toFixed(); // should fail under `strict` as `b` is not definitely assigned

needs to be updated.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

andrewbranch reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@dragomirtitian

Titian Cernicova-Dragomir (dragomirtitian) commented Sep 23, 2019

Copy link
Copy Markdown
Contributor

To use the new PR in playground feature 😊, it seems intelisense has no suggestions ?. for primitive type:

declare let x: string | undefined;
let l = x?.length // no intelisense for length

Play

andrewbranch and Ciantic reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@sandersn Nathan Shively-Sanders (sandersn) self-assigned this Sep 23, 2019
andrewbranch
Andrew Branch (andrewbranch) reviewed Sep 23, 2019
View reviewed changes
Comment thread src/compiler/checker.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

weswigham
Wesley Wigham (weswigham) reviewed Sep 23, 2019
View reviewed changes
Comment thread src/compiler/checker.ts
signature.unionSignatures ? getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype) :
getReturnTypeFromAnnotation(signature.declaration!) ||
(nodeIsMissing((<FunctionLikeDeclaration>signature.declaration).body) ? anyType : getReturnTypeFromBody(<FunctionLikeDeclaration>signature.declaration));
if (signature.isOptionalCall) {

@weswigham Wesley Wigham (weswigham) Sep 23, 2019

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's enough of these fields now that isOptionalCall, hasLiteralTypes, and hasRestParameter should probably be combined into a Flags field of some kind.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@weswigham Wesley Wigham (weswigham) Sep 23, 2019

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related: instantiateSignature doesn't propagate this forward, so rather than a direct access, this needs to follow .target's to check if the uninstantiated signature has a isOptionalCall field, no?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@rbuckton Ron Buckton (rbuckton) Sep 24, 2019

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is correct.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
weswigham
Wesley Wigham (weswigham) reviewed Sep 23, 2019
View reviewed changes

@weswigham Wesley Wigham (weswigham) left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also tests with generic type parameters on the signature being chained on, eg

declare function absorb<T>(): T;
declare const a: { m?<T>(obj: {x: T}): T } | undefined;
const n1: number = a?.m?({x: 12)}); // should be an error (`undefined` is not assignable to `number`)
const n2: number = a?.m?({x: absorb()}); // likewise
const n3: number | undefined = a?.m?({x: 12)}); // should be ok
const n4: number | undefined = a?.m?({x: absorb()}); // likewise

// Also a test showing `!` vs `?` for good measure
let t1 = a?.m?({x: 12});
t1 = a!.m!({x: 12});

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

rbuckton reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@andrewbranch

Andrew Branch (andrewbranch) commented Sep 23, 2019

Copy link
Copy Markdown
Member

Are we planning on including completions that convert . to ?. later, or is there a reason not to? I pulled down this PR and did a quick prototype:

Kapture 2019-09-23 at 14 46 21

OneCyrus, victorgarciaesgi, ranndev, bbugh, ericbf, raon0211, HosseinAgha, codegenerator-cz, and roshandongare reacted with hooray emoji victorgarciaesgi, xiel, ranndev, ericbf, codegenerator-cz, TranquilMarmot, and jamiehaywood reacted with heart emoji
All reactions
  • 🎉 9 reactions
  • ❤️ 7 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@andrewbranch
Prototype
0f5d5d6
andrewbranch
Andrew Branch (andrewbranch) requested changes Sep 23, 2019
View reviewed changes

@andrewbranch Andrew Branch (andrewbranch) left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found a crash in completions. In createCompletionEntry, when converting property access to element access, there’s a line that searches the property access for a DotToken and continues under the assumption that it must exist.

image

TypeError: Cannot read property 'getStart' of undefined
    at createCompletionEntry (tsserver.js:103011:67)
    at getCompletionEntriesFromSymbols (tsserver.js:103078:29)
    at completionInfoFromData (tsserver.js:102945:17)
    at Object.getCompletionsAtPosition (tsserver.js:102900:28)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@rbuckton
Ron Buckton (rbuckton) force-pushed the optionalChainingStage3 branch from 96a91c9 to 0828674 Compare September 30, 2019 09:07
@rbuckton

Ron Buckton (rbuckton) commented Sep 30, 2019

Copy link
Copy Markdown
Contributor Author

TypeScript Bot (@typescript-bot) perf test this

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Sep 30, 2019 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Heya Ron Buckton (@rbuckton), I've started to run the perf test suite on this PR at 0828674. You can monitor the build here. It should now contribute to this PR's status checks.

Update: The results are in!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Sep 30, 2019

Copy link
Copy Markdown
Contributor

Ron Buckton (@rbuckton)
The results of the perf run you requested are in!

Here they are:

Comparison Report - master..33294

Metric master 33294 Delta Best Worst
Angular - node (v12.1.0, x64)
Memory used 331,498k (± 0.02%) 332,910k (± 0.05%) +1,412k (+ 0.43%) 332,347k 333,118k
Parse Time 1.56s (± 0.61%) 1.57s (± 0.48%) +0.01s (+ 0.58%) 1.56s 1.59s
Bind Time 0.80s (± 0.62%) 0.84s (± 0.66%) +0.03s (+ 4.10%) 0.83s 0.85s
Check Time 4.34s (± 0.28%) 4.45s (± 0.60%) +0.11s (+ 2.58%) 4.40s 4.52s
Emit Time 5.25s (± 0.70%) 5.47s (± 0.92%) +0.22s (+ 4.27%) 5.39s 5.59s
Total Time 11.95s (± 0.36%) 12.33s (± 0.57%) +0.38s (+ 3.18%) 12.20s 12.48s
Monaco - node (v12.1.0, x64)
Memory used 346,484k (± 0.01%) 348,075k (± 0.02%) +1,592k (+ 0.46%) 347,970k 348,244k
Parse Time 1.23s (± 0.76%) 1.23s (± 0.56%) -0.00s (- 0.33%) 1.21s 1.24s
Bind Time 0.70s (± 0.63%) 0.72s (± 0.72%) +0.02s (+ 2.71%) 0.71s 0.73s
Check Time 4.40s (± 0.43%) 4.43s (± 0.34%) +0.03s (+ 0.68%) 4.39s 4.46s
Emit Time 2.88s (± 0.75%) 2.99s (± 0.54%) +0.11s (+ 3.93%) 2.94s 3.02s
Total Time 9.21s (± 0.39%) 9.37s (± 0.24%) +0.16s (+ 1.73%) 9.31s 9.42s
TFS - node (v12.1.0, x64)
Memory used 304,629k (± 0.02%) 306,800k (± 0.02%) +2,171k (+ 0.71%) 306,693k 306,902k
Parse Time 0.95s (± 0.63%) 0.96s (± 0.79%) +0.00s (+ 0.10%) 0.94s 0.97s
Bind Time 0.66s (± 0.68%) 0.69s (± 0.83%) +0.03s (+ 4.86%) 0.68s 0.71s
Check Time 3.97s (± 0.64%) 4.01s (± 0.55%) +0.04s (+ 1.08%) 3.98s 4.07s
Emit Time 2.97s (± 0.55%) 3.11s (± 1.10%) +0.14s (+ 4.61%) 3.04s 3.21s
Total Time 8.55s (± 0.33%) 8.77s (± 0.50%) +0.22s (+ 2.54%) 8.66s 8.87s
Angular - node (v8.9.0, x64)
Memory used 350,502k (± 0.01%) 352,094k (± 0.02%) +1,592k (+ 0.45%) 351,853k 352,241k
Parse Time 2.11s (± 0.42%) 2.10s (± 0.53%) -0.01s (- 0.57%) 2.07s 2.12s
Bind Time 0.87s (± 0.77%) 0.90s (± 0.83%) +0.03s (+ 3.09%) 0.89s 0.92s
Check Time 5.19s (± 0.47%) 5.31s (± 0.58%) +0.13s (+ 2.41%) 5.25s 5.40s
Emit Time 5.95s (± 1.41%) 6.27s (± 1.00%) +0.32s (+ 5.42%) 6.13s 6.46s
Total Time 14.12s (± 0.67%) 14.58s (± 0.55%) +0.46s (+ 3.24%) 14.48s 14.87s
Monaco - node (v8.9.0, x64)
Memory used 364,301k (± 0.01%) 366,035k (± 0.01%) +1,735k (+ 0.48%) 365,931k 366,151k
Parse Time 1.56s (± 0.47%) 1.57s (± 0.48%) +0.01s (+ 0.83%) 1.56s 1.59s
Bind Time 0.90s (± 0.68%) 0.92s (± 0.32%) +0.02s (+ 1.89%) 0.91s 0.92s
Check Time 5.23s (± 1.03%) 5.47s (± 0.45%) +0.24s (+ 4.63%) 5.42s 5.54s
Emit Time 3.28s (± 2.45%) 3.06s (± 0.57%) -0.22s (- 6.65%) 3.02s 3.10s
Total Time 10.97s (± 0.37%) 11.02s (± 0.34%) +0.05s (+ 0.47%) 10.97s 11.13s
TFS - node (v8.9.0, x64)
Memory used 321,047k (± 0.01%) 323,267k (± 0.01%) +2,220k (+ 0.69%) 323,199k 323,327k
Parse Time 1.27s (± 0.71%) 1.27s (± 0.64%) +0.01s (+ 0.63%) 1.26s 1.29s
Bind Time 0.78s (± 6.89%) 0.75s (± 1.04%) -0.03s (- 3.97%) 0.73s 0.76s
Check Time 4.52s (± 1.93%) 4.67s (± 0.51%) +0.15s (+ 3.37%) 4.63s 4.74s
Emit Time 3.08s (± 0.73%) 3.22s (± 0.49%) +0.14s (+ 4.41%) 3.18s 3.25s
Total Time 9.64s (± 0.56%) 9.91s (± 0.35%) +0.26s (+ 2.74%) 9.84s 9.99s
Angular - node (v8.9.0, x86)
Memory used 198,645k (± 0.02%) 199,514k (± 0.03%) +869k (+ 0.44%) 199,363k 199,648k
Parse Time 2.04s (± 0.61%) 2.04s (± 0.57%) +0.01s (+ 0.44%) 2.02s 2.08s
Bind Time 0.99s (± 1.01%) 1.04s (± 1.02%) +0.05s (+ 5.07%) 1.02s 1.07s
Check Time 4.72s (± 0.35%) 4.83s (± 0.41%) +0.12s (+ 2.46%) 4.79s 4.87s
Emit Time 5.78s (± 1.35%) 6.05s (± 1.36%) +0.27s (+ 4.71%) 5.95s 6.37s
Total Time 13.52s (± 0.61%) 13.96s (± 0.62%) +0.45s (+ 3.29%) 13.88s 14.30s
Monaco - node (v8.9.0, x86)
Memory used 203,827k (± 0.02%) 204,774k (± 0.02%) +947k (+ 0.46%) 204,680k 204,861k
Parse Time 1.62s (± 0.54%) 1.60s (± 0.36%) -0.02s (- 1.11%) 1.59s 1.61s
Bind Time 0.72s (± 0.68%) 0.76s (± 0.45%) +0.04s (+ 5.39%) 0.76s 0.77s
Check Time 5.32s (± 1.07%) 5.34s (± 0.47%) +0.02s (+ 0.43%) 5.29s 5.39s
Emit Time 2.81s (± 2.88%) 2.87s (± 0.44%) +0.06s (+ 2.10%) 2.85s 2.91s
Total Time 10.47s (± 0.47%) 10.57s (± 0.27%) +0.10s (+ 0.98%) 10.52s 10.65s
TFS - node (v8.9.0, x86)
Memory used 180,612k (± 0.01%) 181,832k (± 0.01%) +1,220k (+ 0.68%) 181,787k 181,890k
Parse Time 1.30s (± 0.46%) 1.32s (± 0.90%) +0.01s (+ 1.07%) 1.29s 1.34s
Bind Time 0.67s (± 0.86%) 0.71s (± 0.78%) +0.04s (+ 5.67%) 0.70s 0.72s
Check Time 4.39s (± 0.49%) 4.43s (± 0.46%) +0.04s (+ 0.87%) 4.38s 4.47s
Emit Time 2.84s (± 0.83%) 2.98s (± 0.91%) +0.14s (+ 4.79%) 2.92s 3.06s
Total Time 9.20s (± 0.25%) 9.43s (± 0.35%) +0.23s (+ 2.48%) 9.38s 9.54s
Angular - node (v9.0.0, x64)
Memory used 350,051k (± 0.02%) 351,729k (± 0.02%) +1,678k (+ 0.48%) 351,586k 351,873k
Parse Time 1.83s (± 0.73%) 1.84s (± 0.58%) +0.01s (+ 0.71%) 1.82s 1.87s
Bind Time 0.82s (± 0.46%) 0.84s (± 0.77%) +0.03s (+ 3.31%) 0.83s 0.86s
Check Time 4.99s (± 0.52%) 5.06s (± 0.70%) +0.07s (+ 1.40%) 5.01s 5.17s
Emit Time 5.71s (± 1.57%) 5.92s (± 0.67%) +0.21s (+ 3.62%) 5.85s 6.00s
Total Time 13.35s (± 0.69%) 13.66s (± 0.23%) +0.31s (+ 2.35%) 13.55s 13.71s
Monaco - node (v9.0.0, x64)
Memory used 364,056k (± 0.02%) 365,826k (± 0.01%) +1,769k (+ 0.49%) 365,723k 365,941k
Parse Time 1.31s (± 0.37%) 1.31s (± 0.72%) -0.00s (- 0.00%) 1.30s 1.34s
Bind Time 0.84s (± 0.73%) 0.87s (± 1.70%) +0.03s (+ 3.80%) 0.85s 0.92s
Check Time 5.25s (± 1.00%) 5.30s (± 1.26%) +0.05s (+ 0.88%) 5.12s 5.38s
Emit Time 2.93s (± 3.80%) 3.10s (± 4.82%) +0.17s (+ 5.83%) 2.98s 3.53s
Total Time 10.34s (± 0.74%) 10.59s (± 0.98%) +0.25s (+ 2.38%) 10.48s 10.91s
TFS - node (v9.0.0, x64)
Memory used 320,733k (± 0.02%) 323,032k (± 0.02%) +2,299k (+ 0.72%) 322,950k 323,182k
Parse Time 1.04s (± 0.72%) 1.04s (± 0.50%) -0.00s (- 0.19%) 1.03s 1.05s
Bind Time 0.66s (± 0.67%) 0.69s (± 0.32%) +0.03s (+ 4.08%) 0.68s 0.69s
Check Time 4.58s (± 0.45%) 4.83s (± 0.45%) +0.24s (+ 5.30%) 4.78s 4.87s
Emit Time 3.23s (± 0.93%) 3.06s (± 0.50%) -0.17s (- 5.14%) 3.03s 3.10s
Total Time 9.52s (± 0.47%) 9.62s (± 0.35%) +0.10s (+ 1.05%) 9.55s 9.67s
Angular - node (v9.0.0, x86)
Memory used 198,782k (± 0.04%) 199,632k (± 0.02%) +850k (+ 0.43%) 199,531k 199,749k
Parse Time 1.73s (± 0.61%) 1.74s (± 0.45%) +0.01s (+ 0.75%) 1.72s 1.75s
Bind Time 0.92s (± 0.53%) 0.96s (± 1.13%) +0.04s (+ 4.11%) 0.94s 0.99s
Check Time 4.41s (± 0.68%) 4.53s (± 0.84%) +0.13s (+ 2.84%) 4.45s 4.60s
Emit Time 5.55s (± 0.77%) 5.72s (± 0.91%) +0.17s (+ 3.06%) 5.65s 5.85s
Total Time 12.61s (± 0.43%) 12.96s (± 0.43%) +0.35s (+ 2.78%) 12.83s 13.07s
Monaco - node (v9.0.0, x86)
Memory used 203,908k (± 0.02%) 204,879k (± 0.02%) +971k (+ 0.48%) 204,756k 204,979k
Parse Time 1.35s (± 0.48%) 1.34s (± 0.65%) -0.01s (- 0.45%) 1.33s 1.36s
Bind Time 0.66s (± 0.51%) 0.68s (± 0.65%) +0.02s (+ 2.87%) 0.67s 0.69s
Check Time 5.14s (± 0.36%) 5.09s (± 1.91%) -0.06s (- 1.13%) 4.89s 5.24s
Emit Time 2.72s (± 0.72%) 2.99s (± 4.95%) +0.26s (+ 9.66%) 2.80s 3.25s
Total Time 9.88s (± 0.31%) 10.09s (± 0.59%) +0.21s (+ 2.18%) 9.99s 10.23s
TFS - node (v9.0.0, x86)
Memory used 180,553k (± 0.02%) 181,748k (± 0.02%) +1,195k (+ 0.66%) 181,654k 181,836k
Parse Time 1.06s (± 0.73%) 1.07s (± 0.77%) +0.01s (+ 0.76%) 1.05s 1.09s
Bind Time 0.63s (± 1.32%) 0.65s (± 0.86%) +0.02s (+ 3.51%) 0.64s 0.66s
Check Time 4.31s (± 0.35%) 4.32s (± 0.57%) +0.01s (+ 0.23%) 4.24s 4.35s
Emit Time 2.83s (± 0.77%) 2.92s (± 1.30%) +0.09s (+ 3.22%) 2.81s 2.99s
Total Time 8.82s (± 0.30%) 8.95s (± 0.44%) +0.13s (+ 1.51%) 8.86s 9.04s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-161-generic
Architecturex64
Available Memory16 GB
Available Memory9 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v12.1.0, x64)
  • node (v8.9.0, x64)
  • node (v8.9.0, x86)
  • node (v9.0.0, x64)
  • node (v9.0.0, x86)
Scenarios
  • Angular - node (v12.1.0, x64)
  • Angular - node (v8.9.0, x64)
  • Angular - node (v8.9.0, x86)
  • Angular - node (v9.0.0, x64)
  • Angular - node (v9.0.0, x86)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v8.9.0, x64)
  • Monaco - node (v8.9.0, x86)
  • Monaco - node (v9.0.0, x64)
  • Monaco - node (v9.0.0, x86)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v8.9.0, x64)
  • TFS - node (v8.9.0, x86)
  • TFS - node (v9.0.0, x64)
  • TFS - node (v9.0.0, x86)
Benchmark Name Iterations
Current 33294 10
Baseline master 10

2hands10fingers and ahagelstein reacted with thumbs up emoji 2hands10fingers reacted with laugh emoji 2hands10fingers, repentsinner, Vages, and xiel reacted with hooray emoji 2hands10fingers, mrcljx, and xiel reacted with heart emoji 2hands10fingers and swftvsn reacted with rocket emoji 2hands10fingers reacted with eyes emoji
All reactions
  • 👍 2 reactions
  • 😄 1 reaction
  • 🎉 4 reactions
  • ❤️ 3 reactions
  • 🚀 2 reactions
  • 👀 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@rbuckton
Merge branch 'master' into optionalChainingStage3
d408e81
@RyanCavanaugh Ryan Cavanaugh (RyanCavanaugh) added this to the TypeScript 3.7.0 milestone Sep 30, 2019
Ron Buckton (rbuckton) added 2 commits September 30, 2019 11:36
@rbuckton
Revert Debug.formatControlFlowGraph helper
c2070be
@rbuckton
Merge branch 'master' into optionalChainingStage3
dfc798f
# Conflicts:
#	src/compiler/checker.ts
#	src/compiler/diagnosticMessages.json
@rbuckton
Ron Buckton (rbuckton) merged commit fcd9334 into master Sep 30, 2019
@hasezoey hasezoey (hasezoey) mentioned this pull request Sep 30, 2019
Refactor checks to optional chaining typegoose/typegoose#56
Closed
@RyanCavanaugh
Ryan Cavanaugh (RyanCavanaugh) deleted the optionalChainingStage3 branch September 30, 2019 19:58
@kube

Chris Feijoo (kube) commented Oct 1, 2019

Copy link
Copy Markdown

❤️

TylerR909, petrbalat, jeremistadler, mrjackdavis, goncharov, ranndev, GugaGongadze, BenjD90, mickdekkers, mikaello, and 42 more reacted with heart emoji
All reactions
  • ❤️ 52 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ekfn

ekfn commented Oct 1, 2019

Copy link
Copy Markdown

Hello, I'm not sure were to leave it, but there are some syntax problems in target code:

https://www.typescriptlang.org/play/?ts=3.7.0-pr-33294-11#code/MYewdgzgLgBAZiEMC8MAUYBcMwFcC2ARgKYBOAlCgHw4DcAsAFCiSyECGpK6YA-NniJlKyGghAZeAOnK0gA

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@andrewbranch

Andrew Branch (andrewbranch) commented Oct 1, 2019 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

ekfn the TS version there is from an earlier commit in this PR. That issue was fixed—you can see it give a proper error in the nightly: https://www.typescriptlang.org/play/?ts=Nightly#code/MYewdgzgLgBAZiEMC8MAUYBcMwFcC2ARgKYBOAlCgHw4DcAsAFCiSyECGpK6YA-NniJlKyGghAZeAOnK0gA

Wait sorry, it looks like the playground doesn’t have the new nightly yet. Here’s the commit where it was fixed, at any rate: e073c05

And here’s a screenshot of it working in master:

image

ekfn and eric-blue reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@j-oliveras

Jordi Oliveras Rovira (j-oliveras) commented Oct 1, 2019

Copy link
Copy Markdown
Contributor

Andrew Branch (@andrewbranch) now it works on playground too.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@andrewbranch

Andrew Branch (andrewbranch) commented Oct 1, 2019

Copy link
Copy Markdown
Member

For me, the playground does show a syntax error, but it’s because it starts to parse as a conditional expression:

image

Subtle difference, but you can tell because the JavaScript emit in the right pane emits a conditional expression with empty true and false sides, and none of the var _a helper variables associated with optional expressions 😄

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@j-oliveras

Jordi Oliveras Rovira (j-oliveras) commented Oct 1, 2019 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Sorry, my comment was that nightly works.

I understand that the last nightly have this PR and #32883 included (or maybe it loads the previous nightly). Something its wrong because it try to parse ?. and ?? as ?: (the last one as a two ?: operators).

Edit: locally with 3.7.0-dev.20191001 I see the same errors as on playground.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@andrewbranch

Andrew Branch (andrewbranch) commented Oct 1, 2019

Copy link
Copy Markdown
Member

image

3.7.0-dev.20191001, shown here, definitely works, but for me loading Nightly on the playground is clearly loading an older build. I’m not sure how to tell for sure what build it is. /cc Orta Therox (@orta)?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@j-oliveras

Jordi Oliveras Rovira (j-oliveras) commented Oct 1, 2019

Copy link
Copy Markdown
Contributor

Tested again locally and it works both (this PR and #32883). Probably I was using another version.

andrewbranch, ExE-Boss, and mnpenner reacted with thumbs up emoji
All reactions
  • 👍 3 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@justinmwarner Justin Warner (justinmwarner) mentioned this pull request Oct 2, 2019
Support Optional Chaining in Typescript Parser typescript-eslint/typescript-eslint#1035
Closed
@orta Orta Therox (orta) mentioned this pull request Oct 16, 2019
Well scoped PRs that added interesting features orta/typescript-notes#18
Open
@r8rsfans75 r8rsfans75 mentioned this pull request Oct 16, 2019
how to do that can babel-eslint support @babel/plugin-proposal-optional-chaining babel/babel-eslint#767
Closed
@isacjunior Isac (isacjunior) mentioned this pull request Oct 24, 2019
Edição 318 - 31/10/2019 braziljs/weekly#294
Closed
@faremax

Faremax (faremax) commented Nov 2, 2019

Copy link
Copy Markdown

I've been looking forward to Optional Chaining in TypeScript for a long time! Looking forward to seeing this PR land. :)

I'm curious, what was the reason that you decided to emit (_a = a) === null || _a === void 0 instead of the shorter (_a = a) == null?

var _a, _b, _c;
(_a = a) == null ? void 0 : _a.b; // optional property access 'a?.b'
(_b = a) == null ? void 0 : _b[x]; // optional element access 'a?.[x]'
(_c = a) == null ? void 0 : _c(); // optional call 'a?.()'

Such as document.all in browser, peculiar results below:

document.all === void 0; // false
document.all === null; // false

// but
document.all == null; // true

If you are using @babel/plugin-proposal-optional-chaining, you can get as (_a = a) == null with option {loose: true }.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@rbiggs

Robert Biggs (rbiggs) commented Dec 4, 2019

Copy link
Copy Markdown

Optional chaining has now reached state 4: https://twitter.com/drosenwasser/status/1202310742436761600. Note, the README hasn't been updated yet.

maggo, mikaello, dragomirtitian, ExE-Boss, SlurpTheo, PavelA85, and develleoper reacted with hooray emoji
All reactions
  • 🎉 7 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Yates (DuYueYu) added a commit to DuYueYu/typescript-book-chinese that referenced this pull request Mar 12, 2020
@DuYueYu
修改拼写错误
633f863
根据提供的PR:(microsoft/TypeScript#33294)
正确拼写:Optional Chaining。
并将其翻译为「可选链」
@DuYueYu Yates (DuYueYu) mentioned this pull request Mar 12, 2020
修改拼写错误 jkchao/typescript-book-chinese#175
Merged
三毛 (jkchao) pushed a commit to jkchao/typescript-book-chinese that referenced this pull request Mar 12, 2020
@DuYueYu
修改拼写错误 (#175)
3011b1c
根据提供的PR:(microsoft/TypeScript#33294)
正确拼写:Optional Chaining。
并将其翻译为「可选链」
@Lxxyx Lxxyx (Lxxyx) mentioned this pull request Dec 18, 2020
fs: refactor to use optional chaining nodejs/node#36524
Closed
2 tasks done
@microsoft Microsoft (microsoft) locked as resolved and limited conversation to collaborators Oct 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Reviewers

@andrewbranch Andrew Branch (andrewbranch) andrewbranch requested changes
@sheetalkamat Sheetal Nandi (sheetalkamat) sheetalkamat requested changes
@sandersn Nathan Shively-Sanders (sandersn) sandersn approved these changes
@weswigham Wesley Wigham (weswigham) weswigham approved these changes
@ahejlsberg Anders Hejlsberg (ahejlsberg) Awaiting requested review from ahejlsberg
+2 more reviewers
@fbartho Frederic Barthelemy (fbartho) fbartho left review comments
@robpalme Rob Palmer (robpalme) robpalme left review comments
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@sandersn Nathan Shively-Sanders (sandersn)

Labels

None yet

Projects

None yet

Milestone

TypeScript 3.7.0

Development

Successfully merging this pull request may close these issues.

Suggestion: "safe navigation operator", i.e. x?.y

Uh oh!

There was an error while loading. Please reload this page.

20 participants

@rbuckton @mariusschulz @SimenB @jwbay @fbartho @ExE-Boss @Jessidhia @orta @typescript-bot @dragomirtitian @andrewbranch @ark120202 @sod @ahejlsberg @kube @ekfn @j-oliveras @faremax @rbiggs @sandersn
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.