TypeScript 支持在JavaScript中覆盖一个返回never的类方法时,将never推断为返回类型,

nwwlzxa7  于 8个月前  发布在  TypeScript
关注(0)|答案(3)|浏览(97)

建议

🔍 搜索词

  • JavaScript return never
  • JavaScript method return never
  • JavaScript override method return never
  • JavaScript abstract method return never

✅ 可实现性检查清单

我的建议满足以下准则:

  • [?] 这不会对现有的TypeScript/JavaScript代码造成破坏性的更改
  • 这不会改变现有JavaScript代码的运行时行为
  • 这可以在不根据表达式的类型生成不同的JS的情况下实现
  • 这不是一个运行时特性(例如库功能,带有JavaScript输出的非ECMAScript语法,JS的新语法糖等)
  • 这个特性将与 TypeScript's Design Goals 的其他部分一致。

⭐ 建议

当实现一个具有返回类型 never 的抽象方法时,如果方法体包含显式的 throw 并且没有包括隐式 return 语句,则具体实现的返回类型应被推断为 never

📃 动机示例

工作台复现:

  1. // @allowJs
  2. // @checkJs
  3. // @noEmit
  4. // @noImplicitAny: false
  5. // @target: ESNext
  6. // @module: ESNext
  7. // @lib: ESNext
  8. // @filename: tokens.d.ts
  9. // Based on: https://github.com/engine262/engine262/tree/main/src/parser/tokens.mjs
  10. export enum Token {
  11. // ...
  12. EOS = 13,
  13. // ...
  14. }
  15. // @filename: Lexer.d.ts
  16. // Based on: https://github.com/engine262/engine262/tree/main/src/parser/Lexer.mjs
  17. import { Token } from "./tokens.js";
  18. export interface ParsedToken {
  19. type: Token;
  20. // ...
  21. }
  22. export abstract class Lexer {
  23. // ...
  24. peek(): ParsedToken;
  25. // ...
  26. abstract createSyntaxError(
  27. context: object | number | undefined,
  28. template: string,
  29. templateArgs: readonly unknown[]
  30. ): SyntaxError;
  31. abstract raiseEarly(
  32. template: string,
  33. context?: object | number,
  34. ...templateArgs: readonly unknown[]
  35. ): SyntaxError;
  36. abstract raise(
  37. // ^?
  38. template: string,
  39. context?: object | number,
  40. ...templateArgs: readonly unknown[]
  41. ): never;
  42. abstract unexpected(
  43. context?: object | number,
  44. ...templateArgs: readonly unknown[]
  45. ): never;
  46. }
  47. // @filename: Parser.js
  48. // Based on: https://github.com/engine262/engine262/tree/main/src/parser/Parser.mjs
  49. import { Lexer } from "./Lexer.js";
  50. import { Token } from "./tokens.js";
  51. export class Parser extends Lexer {
  52. earlyErrors = new globalThis.Set();
  53. createSyntaxError(context = this.peek(), template, templateArgs) {
  54. if (template === "UnexpectedToken" && context.type === Token.EOS) {
  55. template = "UnexpectedEOS";
  56. }
  57. // ...
  58. return new globalThis.SyntaxError(/* ... */);
  59. }
  60. raiseEarly(template, context, ...templateArgs) {
  61. const e = this.createSyntaxError(context, template, templateArgs);
  62. this.earlyErrors.add(e);
  63. return e;
  64. }
  65. // Expected return type: never
  66. // Actual return type: void
  67. raise(template, context, ...templateArgs) {
  68. // ^?
  69. throw this.createSyntaxError(context, template, templateArgs);
  70. }
  71. unexpected(context, ...templateArgs) {
  72. return this.raise(context, "UnexpectedToken", templateArgs);
  73. }
  74. }

💻 用例

在编写 engine262 解析器时获得更好的类型推断。

相关问题

b1payxdu

b1payxdu1#

行为在TypeScript中也是一样的:Playground链接

这是一般的行为,与nevervoid无关:

5cg8jx4n

5cg8jx4n2#

这对我来说似乎是#31470 / #1373的特殊情况。

xpcnnkqh

xpcnnkqh3#

你好,我是 Repro bot 。我可以协助缩小范围并跟踪编译器错误!此评论反映了问题正文中运行的夜间 TypeScript 版本的重现状态。
问题正文代码块由 @ExE-Boss 提供
❌ 失败:-

  • Property 'raise' in type 'Parser' is not assignable to the same property in base type 'Lexer'. Type '(template: any, context: any, ...templateArgs: any[]) => void' is not assignable to type '(template: string, context?: number | object | undefined, ...templateArgs: readonly unknown[]) => never'. Type 'void' is not assignable to type 'never'.
  • Property 'unexpected' in type 'Parser' is not assignable to the same property in base type 'Lexer'. Type '(context: any, ...templateArgs: any[]) => void' is not assignable to type '(context?: number | object | undefined, ...templateArgs: readonly unknown[]) => never'. Type 'void' is not assignable to type 'never'.

历史信息
| 版本 | 重现输出 |
| ------------ | ------------ |
| 4.3.2, 4.4.2, 4.5.2, 4.6.2 | ❌ 失败:-* Property 'raise' in type 'Parser' is not assignable to the same property in base type 'Lexer'. Type '(template: any, context: any, ...templateArgs: any[]) => void' is not assignable to type '(template: string, context?: number | object | undefined, ...templateArgs: readonly unknown[]) => never'. Type 'void' is not assignable to type 'never'.* Property 'unexpected' in type 'Parser' is not assignable to the same property in base type 'Lexer'. Type '(context: any, ...templateArgs: any[]) => void' is not assignable to type '(context?: number | object | undefined, ...templateArgs: readonly unknown[]) => never'. Type 'void' is not assignable to type 'never'. |
| 4.2.2 | ❌ 失败:-* Property 'raise' in type 'Parser' is not assignable to the same property in base type 'Lexer'. Type '(template: any, context: any, ...templateArgs: {}) => void' is not assignable to type '(template: string, context?: number | object | undefined, ...templateArgs: {}) => never'. Type 'void' is not assignable to type 'never'.* Property 'unexpected' in type 'Parser' is not assignable to the same property in base type 'Lexer'. Type '(context: any, ...templateArgs: {}) => void' is not assignable to type '(context?: number | object | undefined, ...templateArgs: {}) => never'. Type 'void' is not assignable to type 'never'. |

展开查看全部

相关问题