TypeScript: never-returning branches should not be considered when determining whether a property is initialized in a constructor

πŸ”Ž Search Terms

constructor, initialization, initialized, 2564, never, throw, error

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried

⏯ Playground Link

https://tsplay.dev/w6Q9yW

πŸ’» Code

const throwParseError = (def: unknown): never => {
    throw new Error(`${def} is not a valid definition`)
}

class Foo {
    // Property 'bar' has no initializer and is not definitely assigned in the constructor.(2564)
    bar: string

    constructor(def: string | null) {
        if (def === null) {
            // this return pattern is useful for narrowing
            // if you remove `return` here, the initialization error goes away
            // but the assignment to bar is then an error
            return throwParseError(null)
        }
        this.bar = def
    }
}

πŸ™ Actual behavior

TypeScript reports that Property 'bar' has no initializer and is not definitely assigned in the constructor.(2564)

πŸ™‚ Expected behavior

TypeScript should identify that in every viable branch of the constructor, bar is assigned.

Additional information about the issue

No response

About this issue

  • Original URL
  • State: closed
  • Created 8 months ago
  • Comments: 22 (10 by maintainers)

Most upvoted comments

I think I’m thinking of another issue that I can’t seem to find on mobile right now, but that issue you linked works as well. πŸ˜„

It seems to work as expected when @MartinJohns 's suggested changes are made:

const throwParseError: (_: unknown) => never = (def: unknown): never => {
    throw new Error(`${def} is not a valid definition`)
}

class Foo {
    // Property 'bar' has no initializer and is not definitely assigned in the constructor.(2564)
    bar: string

    constructor(def: string | null) {
        if (def === null) {
            // this return pattern is useful for narrowing
            // if you remove `return` here, the initialization error goes away
            // but the assignment to bar is then an error
            throwParseError(null)
        }
        this.bar = def
    }
}

https://www.typescriptlang.org/play?ts=5.4.0-dev.20231110#code/MYewdgzgLgBFAWAnEB3ACgQ0RApgUUWUQC4YAKAfVIFcwBrMVMAShgF4A+GMHANx0TtyAExwAzGvUYoWpHv0GcYAbwBQMDXCSpuOFDAJEyAAwAky0WIC+MAJYRuIWBhi8MAG1vCYl22FtQtuDGzKpWqqrA7hgQDgBiICAq6poA9KkwaMgADgJQAJ4wAOQARlhFMPAxjnb+gR62AF4CMBhg3vaOsL51OO6FMRC2AOY8HWBaODCgkFCI1MBQIIgAdGQATACsAGwALKGaMGUkMNCIfsMRhzNnC0uIZJakZxcwAD7c1O7urGqHh7YxCJxOw2GxPt9fil-v90lpOogcFBqIgJtkMFAoAIJp1qLgxF8YGJltwsMgUBdoTC0hlATB8iBqDBEQBbED8GDGRHI1HGSoCHAAGkmtQCtgajQxQQmAiIMGGIBwDgwKAw+Sp1JgcJK1FgCCmgxGYBZODAeqSxzsDn1EzaMFlyw11IQ5Mw2HwhGWZDAXx+To04U1CHsK0t4MsVPC4SAA