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

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

建议

🔍 搜索词

  • 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

📃 动机示例

工作台复现:

// @allowJs
// @checkJs
// @noEmit
// @noImplicitAny: false
// @target: ESNext
// @module: ESNext
// @lib: ESNext

// @filename: tokens.d.ts
// Based on: https://github.com/engine262/engine262/tree/main/src/parser/tokens.mjs
export enum Token {
	// ...
	EOS = 13,
	// ...
}

// @filename: Lexer.d.ts
// Based on: https://github.com/engine262/engine262/tree/main/src/parser/Lexer.mjs
import { Token } from "./tokens.js";

export interface ParsedToken {
	type: Token;
	// ...
}

export abstract class Lexer {
	// ...
	peek(): ParsedToken;

	// ...
	abstract createSyntaxError(
		context: object | number | undefined,
		template: string,
		templateArgs: readonly unknown[]
	): SyntaxError;
	abstract raiseEarly(
		template: string,
		context?: object | number,
		...templateArgs: readonly unknown[]
	): SyntaxError;
	abstract raise(
	//          ^?
		template: string,
		context?: object | number,
		...templateArgs: readonly unknown[]
	): never;
	abstract unexpected(
		context?: object | number,
		...templateArgs: readonly unknown[]
	): never;
}

// @filename: Parser.js
// Based on: https://github.com/engine262/engine262/tree/main/src/parser/Parser.mjs
import { Lexer } from "./Lexer.js";
import { Token } from "./tokens.js";

export class Parser extends Lexer {
	earlyErrors = new globalThis.Set();

	createSyntaxError(context = this.peek(), template, templateArgs) {
		if (template === "UnexpectedToken" && context.type === Token.EOS) {
			template = "UnexpectedEOS";
		}
		// ...
		return new globalThis.SyntaxError(/* ... */);
	}

	raiseEarly(template, context, ...templateArgs) {
		const e = this.createSyntaxError(context, template, templateArgs);
		this.earlyErrors.add(e);
		return e;
	}

	// Expected return type:	never
	//   Actual return type:	void
	raise(template, context, ...templateArgs) {
	// ^?
		throw this.createSyntaxError(context, template, templateArgs);
	}

	unexpected(context, ...templateArgs) {
		return this.raise(context, "UnexpectedToken", templateArgs);
	}
}

💻 用例

在编写 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'. |

相关问题