Skip to content

Inconsistent behavior with type inference for generic contraints #58009

Closed as not planned

Description

🔎 Search Terms

type, type inference, generic constraints

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries. Tested on version 4.3.3 and 5.5.0-dev.20240330 (the latest was available at the time of the issue creation).

⏯ Playground Link

Playground here

💻 Code

1. // Setup
2. type ExampleType = { property: boolean };
3. let reference: ExampleType = { property: true };
4. 
5. // The type that introduces the unexpected behavior.
6. type CopyType<T> = {
7.   [P in keyof T]: T[P];
8. };
9. 
10. // Check if the assignment works.
11. let check: CopyType<ExampleType> = { property: true };
12. 
13. // Test with generic constraints.
14. function test<T extends ExampleType>(param: CopyType<T>) {
15.   param.property = true; // It compiles.
16.   param.anotherProperty = true; // It does not compile, as expected.
17.   param = { property: true }; // It does not compile, not expected.
18.   let check: CopyType<T> = { property: true }; // It does not compile, not expected.
19. }

🙁 Actual behavior

The compiler partially infers the type: it doesn't compile as expected when I do the assignment param.anotherProperty = true. This makes me think that there is some understanding of the type thanks to the generic constraint.
In the other two lines (17 and 18) it doesn't compile with the corresponding error:

  • Type '{ property: true; }' is not assignable to type 'CopyType'.

🙂 Expected behavior

I would expect a consistent behavior:

  • If it should be capable of inferring the type, that the code compiles.
  • If something is incorrect in that definition, that also line 16 doesn't compile.

Additional information about the issue

I came out with this example from an unexpected behavior using ts-essential, that has more unexpected behaviors:

// Setup
type ExampleType = { propertyA: boolean; propertyB: number };
type KeepBooleanProperties<T> = PickProperties<T, boolean>;
let check1: KeepBooleanProperties<ExampleType> = { propertyA: true }; // Compiles, expected.
let check2: KeepBooleanProperties<ExampleType> = { propertyA: true, propertyB: 1 }; // It doesn't compile, expected.

// Test with generic constraints.
function test<T extends ExampleType>(param: KeepBooleanProperties<T>) {
  param.propertyA = true; // It doesn't compile, not expexted.
  param.anotherProperty = true; // It does not compile, expected.
  param = { propertyA: true }; // It does not compile, not expected.
  let check: CopyType<T> = { property: true }; // It does not compile, not expected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    QuestionAn issue which isn't directly actionable in code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions