建议
🔍 搜索词
- 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 解析器时获得更好的类型推断。
3条答案
按热度按时间b1payxdu1#
行为在TypeScript中也是一样的:Playground链接
这是一般的行为,与
never
和void
无关:5cg8jx4n2#
这对我来说似乎是#31470 / #1373的特殊情况。
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'.
|