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 — Strict property initialization checks in classes by ahejlsberg · Pull Request #20075 · microsoft/TypeScript

Conversation

@ahejlsberg

@ahejlsberg Anders Hejlsberg (ahejlsberg) commented Nov 16, 2017 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member

This PR implements a new --strictPropertyInitialization compiler option to guard against uninitialized properties in class instances. Strict property initialization checking verifies that each instance property declared in a class either (a) has a type that includes undefined or (b) has an explicit initializer or an assignment to the property in the constructor. The --strictPropertyInitialization option has no effect unless --strictNullChecks is also enabled.

The --strictPropertyInitialization switch is part of the --strict family of switches, meaning that it defaults to on in --strict mode. This PR is therefore a breaking change only in --strict mode.

In this example

// Compile with --strict
class Test {
    a: number;  // Error, property not initialized
    b?: string;  // Ok, type includes undefined
}

an error is reported on property a because its type doesn't include undefined and the property declaration doesn't specify an initializer or assign a value to the property in the constructor. The error can be fixed by changing the type of a to include undefined, by specifying an initial value for a, or by assigning a value to a in the constructor. For example, this is ok:

// Compile with --strict
class Test {
    a: number = 0;  // Ok
    b?: string;
}

A strict property initialization check is satisfied by assignments in the constructor only when all possible code paths include assignments to the particular property.

// Compile with --strict
class Test {
    a: number;
    constructor(startAtZero: boolean) {
        if (startAtZero) {
            this.a = 0;
        }
        else {
            this.a = 1;
        }
    }
}

In the example above, an error would occur if either of the if statement branches omitted the assignment to this.a.

Strict property initialization checks guard against observing uninitialized properties in the constructor body. For example:

// Compile with --strict
class Test {
    a: number;
    constructor() {
        let x = this.a;  // Error
        this.a = 0;
    }
}

Strict property initialization checks also guard against observing uninitialized properties after the constructor returns. However, it is possible to observe uninitialized properties in methods that are called from the constructor (or from a base constructor). For example:

// Compile with --strict
class Test {
    a: number;
    constructor() {
        this.foo();
        this.a = 0;
    }
    foo() {
        // Uninitialized value of 'a' observable here
    }
}

Strict property initialization checks only apply to properties that are declared with proper identifiers. It does not apply to properties with computed names or properties with names specified as string or numeric literals (this is analogous to how control flow analysis isn't applied to properties accessed using obj["foo"] syntax).

// Compile with --strict
class Test {
    a: number;  // Error, not initialized
    "hello world": number;  // No check
}

In cases where the properties of a class instance are initialized by external means (such as dependency injection) or where it is known that an initialization method is always called before other methods, strict property initialization checks can be suppressed by including definite assignment assertions (#20166) in the declarations of the properties.

// Compile with --strict
class C {
    a!: number;  // Use ! to suppress error
    b!: string;  // Use ! to suppress error
    initialize() {
        this.a = 0;
        this.b = "hello";
    }
}

Alternatively, // @ts-ignore comments can be used to suppress the errors, or the code can simply be compiled without the --strictPropertyInitialization option.

Fixes #8476.

Sorry, something went wrong.

Uh oh!

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

SlurpTheo, timocov, raveclassic, j-oliveras, helmutschneider, gcnew, nicolashenry, beakbeak, kdama, seikichi, and 71 more reacted with thumbs up emoji sampsyo, kdama, sanex3339, eugirdor, mariusschulz, krzkaczor, danizord, listepo-alterpost, and x-strong reacted with laugh emoji raveclassic, j-oliveras, sampsyo, nicolashenry, beakbeak, kdama, KonanMentor, Nipheris, sanex3339, eugirdor, and 10 more reacted with hooray emoji raveclassic, alexrock, sampsyo, nicolashenry, peterkelly, kdama, eugirdor, mariusschulz, itsMapleLeaf, krzkaczor, and 11 more reacted with heart emoji
All reactions
  • 👍 81 reactions
  • 😄 9 reactions
  • 🎉 20 reactions
  • ❤️ 21 reactions
Anders Hejlsberg (ahejlsberg) added 6 commits November 16, 2017 10:35
@ahejlsberg
Attach return control flow graph to contructor declaration nodes
f1762a0
@ahejlsberg
Add strict property initialization checks
5f6d7f3
@ahejlsberg
Mark returnFlowNode property as internal
c11969f
@ahejlsberg
Add --strictPropertyInitialization compiler option
8cbff01
@ahejlsberg
Update tests
3357aae
@ahejlsberg
Accept new baselines
3a7a99f
@ahejlsberg Anders Hejlsberg (ahejlsberg) mentioned this pull request Nov 16, 2017
Check non-undefined properties are initialized in the constructor with --strictNullChecks #8476
Closed
@ahejlsberg
Anders Hejlsberg (ahejlsberg) requested review from Daniel Rosenwasser (DanielRosenwasser), Ryan Cavanaugh (RyanCavanaugh) and Mohamed Hegazy (mhegazy) November 16, 2017 21:36
Anders Hejlsberg (ahejlsberg) added 4 commits November 16, 2017 17:30
@ahejlsberg
Exclude static properties
190f99e
@ahejlsberg
Revise return control flow graph construction logic
041d045
@ahejlsberg
Add tests
4141a37
@ahejlsberg
Accept new baselines
49d6ddf
@RyanCavanaugh

Ryan Cavanaugh (RyanCavanaugh) commented Nov 17, 2017

Copy link
Copy Markdown
Member

Add check for abstract properties

dasois 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.

@itsMapleLeaf

itsMapleLeaf commented Nov 17, 2017

Copy link
Copy Markdown

Note that strict property initialization checks only guard against observing uninitialized properties after the constructor returns. It is still possible to observe uninitialized properties in methods that are called from the constructor (or from a base constructor).

Is there a reason TS can't check if the called functions access the uninitialized value, then report the error in the constructor?

All reactions

Sorry, something went wrong.

Uh oh!

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

@weswigham

Wesley Wigham (weswigham) commented Nov 17, 2017

Copy link
Copy Markdown
Member

@kingdaro we only do control flow analysis across function bounds for immediately invoked function expressions; to do otherwise would be error-prone in the presence of aliasing, so we conservatively avoid doing so.

itsMapleLeaf 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.

Anders Hejlsberg (ahejlsberg) added 4 commits November 17, 2017 13:21
@ahejlsberg
Exclude abstract properties from strict initialization checks
85ea473
@ahejlsberg
Add test
20b21d3
@ahejlsberg
Accept new baselines
6ba8c57
@ahejlsberg
Fix lint error
86871c7
RyanCavanaugh
Ryan Cavanaugh (RyanCavanaugh) approved these changes Nov 17, 2017
View reviewed changes
@ahejlsberg
Merge branch 'master' into strictPropertyInitialization
8c4c529
@mhegazy Mohamed Hegazy (mhegazy) mentioned this pull request Nov 17, 2017
Design Meeting Notes, 11/17/2017 #20117
Closed
Anders Hejlsberg (ahejlsberg) added 4 commits November 18, 2017 08:49
@ahejlsberg
Simplify checkPropertyAccessExpressionOrQualifiedName
dccf57f
@ahejlsberg
Add definite assignment checks for property accesses in constructor body
0fbf36c
@ahejlsberg
Add test
82fd5a8
@ahejlsberg
Accept new baselines
87a8d41
mhegazy
Mohamed Hegazy (mhegazy) approved these changes Nov 20, 2017
View reviewed changes
@ahejlsberg
Anders Hejlsberg (ahejlsberg) merged commit 148dc4e into master Nov 20, 2017
@ahejlsberg
Anders Hejlsberg (ahejlsberg) deleted the strictPropertyInitialization branch November 20, 2017 18:44
@ahejlsberg Anders Hejlsberg (ahejlsberg) mentioned this pull request Nov 20, 2017
Definite assignment assertions #20166
Merged
@weswigham Wesley Wigham (weswigham) mentioned this pull request Nov 20, 2017
Fix build in the presence of definite assignment analysis #20170
Merged
@abramobagnara

abramobagnara commented Nov 21, 2017 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown

What about initializing helpers?
Suppose that constructor calls a method that complete the initialization (e.g. the developer has put this initialization in a separate method because it should be called also after object construction).
What you propose to handle this case?

mihailik 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.

@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented Nov 21, 2017

Copy link
Copy Markdown
Member Author

abramobagnara I'd propose one of:

  • Don't use the --strictPropertyInitialization option.
  • Rewrite the code to include initializers or assignments in the constructor.
  • Use definite assignment assertions introduced by Definite assignment assertions #20166.
All reactions

Sorry, something went wrong.

Uh oh!

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

@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented Nov 21, 2017

Copy link
Copy Markdown
Member Author

I have edited the PR description to reflect #20166.

All reactions

Sorry, something went wrong.

Uh oh!

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

@mihailik

mihailik commented Nov 21, 2017

Copy link
Copy Markdown
Contributor

The --strictPropertyInitialization option has no effect unless --strictNullChecks is also enabled.

Will be really useful to have a warning in such case.

All reactions

Sorry, something went wrong.

Uh oh!

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

@mihailik

mihailik commented Nov 21, 2017 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Contributor

Also, does this PR handle cases where error is thrown before all fields initialised?

class Car {
  color: string;

  constructor() {
    if (!carsSupportedByBrowser) {
     console.log('Cars not supported');
     throw new Error('Not supported');
    }

    this.color = 'red';
  }
}
All reactions

Sorry, something went wrong.

Uh oh!

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

@mihailik

mihailik commented Nov 21, 2017

Copy link
Copy Markdown
Contributor

And a quirkier variation of previous case:

class Car {
  color: string;

  constructor() {
    if (!carsSupportedByBrowser) {
     console.log('Cars not supported ', this); <--- see we expose instance with uninitialised color
     throw new Error('Not supported');
    }

    this.color = 'red';
  }
}
All reactions

Sorry, something went wrong.

Uh oh!

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

@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented Nov 21, 2017

Copy link
Copy Markdown
Member Author

Also, does this PR handle cases where error is thrown before all fields initialised?

It is fine to throw an exception before all properties are initialized, and yes you can expose an object that isn't fully initialized to the outside (just like you can call methods before the object is fully initialized).

mihailik and brunocribeiro 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.

@mhegazy Mohamed Hegazy (mhegazy) mentioned this pull request Nov 22, 2017
TS 2.7-- Add new flags #20227
Closed
8 tasks done
@trotyl Trotyl Yu (trotyl) mentioned this pull request Nov 28, 2017
Enable strictNullChecks mode for aio codebase angular/angular#20646
Closed
@azu azu (azu) mentioned this pull request Dec 3, 2017
Docs: Store/State class pattern almin/almin#303
Open
@gcnew Marin Marinov (gcnew) mentioned this pull request Dec 6, 2017
Exhaustiveness checking with classes #20512
Closed
@chandu0101 Chandra Sekhar Kode (chandu0101) mentioned this pull request Dec 11, 2017
generated typescript files are not compiling with latest version(2.7.0-dev.20171207) of ts google/flatbuffers#4533
Closed
@cyrilletuzi Cyrille Tuzi (cyrilletuzi) mentioned this pull request Dec 17, 2017
Several issues with strict property checks and definite assignement assertion #20740
Closed
@j-oliveras Jordi Oliveras Rovira (j-oliveras) mentioned this pull request Dec 20, 2017
Class members that are non-optional or are not unioned with undefined don't require initialisation. #20829
Closed
@thorn0 Georgii Dolzhykov (thorn0) mentioned this pull request Dec 24, 2017
TypeScript 2.7: exclamation marks in property declarations aren't parsed prettier/prettier#3561
Closed
@jfnadeau Jean-Francois Nadeau (jfnadeau) mentioned this pull request Feb 21, 2018
File Uploader ulaval/modul-components#80
Merged
@RyanCavanaugh Ryan Cavanaugh (RyanCavanaugh) mentioned this pull request Mar 13, 2018
strictPropertyInitialization does not work on instance fields with string names #22486
Closed
@loicraux loicraux mentioned this pull request Apr 24, 2018
Update documentation to mention that --strictNullChecks flag is necessary for --strictPropertyInitialization to have an effect #23659
Closed
@ikatyang Ika (ikatyang) mentioned this pull request May 20, 2018
Preserve quotes around property names in TypeScript classes prettier/prettier#4516
Closed
@microsoft Microsoft (microsoft) locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Reviewers

@RyanCavanaugh Ryan Cavanaugh (RyanCavanaugh) RyanCavanaugh approved these changes
@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) Awaiting requested review from DanielRosenwasser
+1 more reviewer
@mhegazy Mohamed Hegazy (mhegazy) mhegazy approved these changes
Reviewers whose approvals may not affect merge requirements

Uh oh!

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

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Check non-undefined properties are initialized in the constructor with --strictNullChecks

Uh oh!

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

7 participants

@ahejlsberg @RyanCavanaugh @itsMapleLeaf @weswigham @abramobagnara @mihailik @mhegazy
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.