-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Open
Labels
Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureHas ReproThis issue has compiler-backed repros: https://aka.ms/ts-reprosThis issue has compiler-backed repros: https://aka.ms/ts-reprosSuggestionAn idea for TypeScriptAn idea for TypeScript
Description
Suggestion
🔍 Search Terms
- JavaScript return never
- JavaScript method return never
- JavaScript override method return never
- JavaScript abstract method return never
✅ Viability Checklist
My suggestion meets these guidelines:
- [?] This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
⭐ Suggestion
When implementing an abstract method with a signature that returns never
, the concrete implementation should have its return type inferred as never
if the method body contains an explicit throw
and no return
statements including the implicit return
.
📃 Motivating Example
// @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);
}
}
💻 Use Cases
To get better type inference while working on engine262’s parser.
Relevant issues
Metadata
Metadata
Assignees
Labels
Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureHas ReproThis issue has compiler-backed repros: https://aka.ms/ts-reprosThis issue has compiler-backed repros: https://aka.ms/ts-reprosSuggestionAn idea for TypeScriptAn idea for TypeScript