Skip to content
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

Missing error on generic type parametrisation of generic function #59143

Open
ConnorDuvalS opened this issue Jul 5, 2024 · 0 comments
Open

Comments

@ConnorDuvalS
Copy link

πŸ”Ž Search Terms

"generics", "functions", "unions"

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried (v3.3.3 and v5.5.2, though v3.3.3 did not error on Case 6), and I reviewed the entire FAQ

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.5.2#code/JYOwLgpgTgZghgYwgAgJLIN4ChnLgLk2WABNCQBXAWwCNoBuZANzgBsKJCBnMKUAc2QBfejmQ1CGYmWSVaDZmw6EaAe1WsIcEMNG4Ek6eWp0ousTKmlj8syLGci93DEPXkPPiEFCs9rGAAngAOKABSyAC8RADaANLEOgDWEIGqMGgAuoSo8ZnIEAAekCAkXETucqbCyAD8yAnkEEzQwjEpaRmomYwA9L3IAERwg8gAPkM0oxODCNNDJINYWDAUIAhgwKo6MACMADwAGgXFEKXlHeloAHwAFIWEhwA0Rmgxh-lFJWUVMqAwrQASjV6sCmi0oABKTBiKAQMAUKAgUS+Fa7W7DQYvADMkL6AyocBS5S4Z1Jy1W60222QMAATEcTt9ymE7g9kM9kIEcu9MtDsLg4QikSiKXSMSMXlYZNiXix2I4AOSK4R45D9ZCE4keMkQFbiwZTKWvWWKBWEeCsUmq-GaokQEm6ilrDZbHbYxlfM4-Vn3R78sS9ABUyAAwnBrbtkEGBnt7ji1RquAALVQUVgkWSqMDiFDaApQKCqKCBkPh6106Oxg6HNkJ20ptMZrM5uh4HTQIsl3DBsMRlDYqu0mvIABkyFuYUhdeQuIbqfTmZA2dz7YLXdLfetABYh3t9r7CvX1QT7Y6QKSAHTX4gpzfllAAVj3BwiMxggxniuxisTA0bi6rvmnbFssPZlv2yAAGx7gytbxr8hCmvKyjILwHA2ie67FuUCDFnCGysIE96QQA7LBB4ztKSFykojjoSgQh-h4C7Nm2wGFqBvhAA

πŸ’» Code

interface I {
  a: { id: number; value: string };
  b: { id: number; value: boolean };
  c: { id: number };
  d: { id: number };
  e: { };
  f: { id: string }
};

type J = { [K in keyof I]: I[K] extends { id: number } ? K : never }[keyof I]; // "a" | "b" | "c" | "d"

function f1<X extends keyof I>(x: X, id: I[X] extends { id: infer R } ? R : never) {
  return;
}

f1("a", 3); // makes sense

function f2<X extends J>(x: X, y: I[X]) {
  return;
}

f2("a", { id: 3, value: '' }); // makes sense
f2("b", { id: 3, value: false }); // makes sense

function f3<X extends J>(x: X) {
  /* Case 1 */ f1(x, 3); // should not be an error
  /* Case 2 */ f1<X>(x, 3); // should not be an error
  /* Case 3 */ f1<X & (J)>(x, 3); // should not be an error
  /* Case 4 */ f1<J>(x, 3); // makes sense... ish
  /* Case 5 */ f1<J | "f">(x, '3'); // should be an error

  /* Case 6 */ f2<X>(x, { id: 3, value: true }); // errors correctly
  /* Case 7 */ f2<J>(x, { id: 3, value: true }); // should be an error
}

πŸ™ Actual behavior

Cases shown in f3:
Cases 1 & 2 & 3: Errors with message

Argument of type 'number' is not assignable to parameter of type 'I[X] extends { id: infer R; } ? R : never'.

Cases 4 & 5: No error
Case 6: Errors with message

Argument of type '{ id: number; value: true; }' is not assignable to parameter of type 'I[X]'.
  Type '{ id: number; value: true; }' is not assignable to type 'never'.
    The intersection '{ id: number; value: string; } & { id: number; value: boolean; } & { id: number; } & { id: number; }' was reduced to 'never' because property 'value' has conflicting types in some constituents.

Case 7: No error

πŸ™‚ Expected behavior

As shown in the comments within f3:
Case 1 & 2: Should not be an error, X is narrowed to only be values for which a number works.
Case 3: Should not be an error, whilst X & J is narrowed to only be values for which a number works.
Case 4: Blankets the type, making the function work at the cost that it makes any additional type inference impossible. Due to I["a"] and I["b"], you would not be able to add a parameter of type I[X] to this function (as seen in cases for f2) as it has required types that do not exist in all I[J].
Case 5: Should be an error. The type of f1<X> for a generic X should be a union of functions with a specific input, not a function with a union input.
Case 6: Expected behaviour is actual behaviour.
Case 7: Should be an error for the same reason as Case 5 and Case 6.

Additional information about the issue

My assumption for the first three cases is that this was done to handle the case that X is any but, be that as it may, I do not see a similar explanation for the other cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant