Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent Type Narrowing with never Return Type Between Arrow and Traditional Functions #58073

Closed
akeldamas opened this issue Apr 4, 2024 · 2 comments

Comments

@akeldamas
Copy link

akeldamas commented Apr 4, 2024

🔎 Search Terms

"Inconsistent", "Arrow", "Narrowing", "Type Guard"

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about version 3.3 till nightly version 5.5.0-dev.20240404. The version I am using is 5.4.3.

⏯ Playground Link

https://www.typescriptlang.org/play?noImplicitAny=false&strictNullChecks=false&strictFunctionTypes=false&strictPropertyInitialization=false&strictBindCallApply=false&noImplicitThis=false&noImplicitReturns=false&alwaysStrict=false&experimentalDecorators=true&target=7&jsx=0&module=1&allowSyntheticDefaultImports=true&ts=5.4.3#code/MYewdgzgLgBFAWAnEB3Ago5KYF4YAoBKALhjAFMA3cxXAPhgG8BYAKBjiVTPOwFFMIRPgBEAZRABbcjAHJEIwgG42AXzZsAZgFcwwKAEtwnLADFd+o2AIke1Wi3YnuFfoOEiA8ghqz3ilVZ1VjZgABsAQwgIGFMQECY2DgAHRANKCKgZACMI4QAPUmg0sABzGAAfMm0wsNtigzLEpw4DTQJ83Bw8MBq65o5B53RBFCJAoeCkwcRyKG1Ea3ylGAB6VZgAFXgDGKgAT2SZGnkIADpp4KnWcKiYgCE8gZhU9MyZTXj8faKoEvKqr1avU-o1yo4hm0CPsuj0+oRnkMEGYLIZwONphxrkNZvNFjB9it1lsdjEUEIANbnS5qIA

💻 Code

const arrow = (): never => {
  throw new Error("Error");
};

function traditional(): never {
  throw new Error("Error");
}

class Foo {
  bar(x: string | null): string {
    if (x === null) {
      arrow();
    }
    return x; //<- Doesn't work.
  }

  private barPrivate(x: string | null): string {
    if (x === null) {
      arrow();
    }
    return x; //<- Doesn't work.
  }

  barThrow(x: string | null): string {
    if (x === null) {
      throw arrow();
    }
    return x; //<- Works.
  }

  barReturn(x: string | null): string {
    if (x === null) {
      return arrow();
    }
    return x; //<- Works.
  }

  baz(x: string | null): string {
    if (x === null) {
      traditional();
    }
    return x; //<- Works.
  }

  private bazPrivate(x: string | null): string {
    if (x === null) {
      traditional();
    }
    return x; //<- Works.
  }

  bazThrow(x: string | null): string {
    if (x === null) {
      throw traditional();
    }
    return x; //<- Works.
  }

  bazReturn(x: string | null): string {
    if (x === null) {
      return traditional();
    }
    return x; //<- Works.
  }
}

🙁 Actual behavior

I created a separate function to handle errors, which also involves throwing them. I expected that explicitly stating the return type as never would lead Typescript to infer this and accordingly narrow the types on the variable. However, contrary to my expectations, I received a type error, which seemed to disregard the type guard.

🙂 Expected behavior

I expect that type narrowing behaves identically for arrow functions and traditional functions.

Additional information about the issue

I'm not entirely sure if this is a bug or merely expected behaviour. However, I am confident that type narrowing for arrow and traditional functions should behave similarly. If I'm mistaken, please let me know.

I attempted to replicate this in the playground, but it seems not all configuration settings are available there, so I am including my TypeScript configuration. Additionally, here is some extra environment information.

VSCODE:

Version: 1.87.2 (user setup)
Commit: 863d2581ecda6849923a2118d93a088b0745d9d6
Date: 2024-03-08T15:20:17.278Z
Electron: 27.3.2
ElectronBuildId: 26836302
Chromium: 118.0.5993.159
Node.js: 18.17.1
V8: 11.8.172.18-electron.0
OS: Windows_NT x64 10.0.22631

Package.json

  "devDependencies": {
    "@types/node": "^20.11.28",
    "@types/pg": "^8.11.2",
    "@types/progress": "^2.0.7",
    "ts-node": "^10.9.2",
    "tslib": "^2.6.2",
    "typescript": "^5.4.2"
  },
  "dependencies": {
    "csvtojson": "^2.0.10",
    "dotenv": "^16.4.5",
    "es7": "npm:@elastic/elasticsearch@^7.17.0",
    "pg": "^8.11.3",
    "progress": "^2.0.3"
  }

Ts Config:

{
  "compilerOptions": {
    "target": "ES2020",
    "experimentalDecorators": true,
    "module": "commonjs",
    "baseUrl": "./src",
    "types": ["node"],
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  },
  "exclude": ["node_modules"]
}

@nmain
Copy link

nmain commented Apr 4, 2024

🔎 Search Terms
"Inconsistent", "Arrow", "Narrowing", "Type Guard"

The second result when seearching for those is #51075, which this is a duplicate of.

@akeldamas
Copy link
Author

Thanks my bad.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants