Skip to content

Version 5.0.4 -> 5.1.3 Regression when using generic types #54805

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

Open
chentsulin opened this issue Jun 28, 2023 · 2 comments
Open

Version 5.0.4 -> 5.1.3 Regression when using generic types #54805

chentsulin opened this issue Jun 28, 2023 · 2 comments
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@chentsulin
Copy link

chentsulin commented Jun 28, 2023

Bug Report

πŸ”Ž Search Terms

Generic, 5.1.3

πŸ•— Version & Regression Information

  • This changed between versions 5.0.4 and 5.1.3

⏯ Playground Link

https://www.typescriptlang.org/play?ts=5.1.3#code/C4TwDgpgBAMhAeBLAxgQwDYGED2BbXqAdgCYA8AKgAqojrarEB8UAvFAEoTLYBOZAzsB6JCAcwA0UQhABuEHowDcAKGWhIUAJKF+84OQTBqtesVYcIDbIXQhSAbyjBDALiiDhYqAF8lqgGYAroTIwIjWUMg8ls44+ERk5IwAFACUbnBIaFh4BCQUzPbKUCVQ0cCBPIRQ9t4q3qrcOsBaAHIAygCi7OQA+uSdABp9mADyALLjAIKtACIZCCgYcXlk2ro8+obGdAzMLMWR0aixuQlpikA

πŸ’» Code

type LexicalCommand<TPayload> = Record<string, never>;

type InsertTextPayload = Readonly<{ text: string }>;

function createCommand<T>(): LexicalCommand<T> {
    return {};
}

const INSERT_TEXT_COMMAND: LexicalCommand<InsertTextPayload> =
  createCommand();

πŸ™ Actual behavior

The type of INSERT_TEXT_COMMAND is LexicalCommand<TPayload> in 5.1.3 (but LexicalCommand<InsertTextPayload> in 5.0.4).

πŸ™‚ Expected behavior

The type of INSERT_TEXT_COMMAND should be LexicalCommand<InsertTextPayload>.

@fatcerberus
Copy link

fatcerberus commented Jun 28, 2023

I can't say why the behavior changed, but this code is fundamentally problematic: LexicalCommand doesn't use its type parameter so it doesn't matter what type you give for TPayload (all Record<string, never> are equivalent). TS tends to misbehave around phantom types because generic inference is structural1. If you actually use TPayload in the type then you get the expected inference in all TS versions.

Footnotes

  1. It's like solving for x in 0 * x = 0; any value is a valid solution. ↩

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Jun 28, 2023
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 5.2.1 milestone Jun 28, 2023
@RyanCavanaugh
Copy link
Member

The report as written is benign, but the declaration emit is messed up. If the input is modified to remove the type annotation:

type LexicalCommand<TPayload> = Record<string, never>;

type InsertTextPayload = Readonly<{ text: string }>;

function createCommand<T>(): LexicalCommand<T> {
    return {};
}

const INSERT_TEXT_COMMAND = createCommand();

then the output is

type LexicalCommand<TPayload> = Record<string, never>;
type InsertTextPayload = Readonly<{
    text: string;
}>;
declare function createCommand<T>(): LexicalCommand<T>;
declare const INSERT_TEXT_COMMAND: LexicalCommand<TPayload>;

which refers to the unbound TPayload

@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label Jun 29, 2023
@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label Jul 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
5 participants