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

Narrow conditional type #59294

Closed
6 tasks done
steffenag opened this issue Jul 16, 2024 · 2 comments
Closed
6 tasks done

Narrow conditional type #59294

steffenag opened this issue Jul 16, 2024 · 2 comments
Labels
Duplicate An existing issue was already created

Comments

@steffenag
Copy link

πŸ” Search Terms

Conditional type inference narrow

βœ… Viability Checklist

⭐ Suggestion

A conditional type should be narrowed when possible.

βœ… When calling foo in the example below, types are as expected - We always require the x property to be defined in the object payload, and when we specify mode Y, we also require the y property to be defined

Within the foo function In the example below, the point type is completely useless
πŸ”΄ I expect the point type to be narrowed to Pick<TPoint, 'x' | 'y'> = { x: number; y: number } when we know that mode: 'Y', but I get a type error when I try to access any property of the object:
Property 'y' does not exist on type 'Pick<TPoint, TMode extends "Y" ? "x" | "y" : "x">'.(2339)
πŸ”΄ I expect x to always be accessible from the point, but I get a type error when I try to access the property of the object:
Property 'x' does not exist on type 'Pick<TPoint, TMode extends "Y" ? "x" | "y" : "x">'.(2339)

πŸ“ƒ Motivating Example

We would now be able to write functions where two or more parameters depend on each other:

type TPoint = { x: number; y: number; z: number };

const foo = <TMode extends 'X' | 'Y'>(
  mode: TMode,
  point: Pick<TPoint, TMode extends 'Y' ? 'x' | 'y' : 'x'>,
) => {
  if (mode === 'Y') {
    return point.x + point.y;
  }

  return point.x;
};


foo('X', { x: 1 });

// @ts-expect-error: Object literal may only specify known properties, and 'y' does not exist in type 'Pick<TPoint, "x">'.(2353)
foo('X', { x: 1, y: 2 });

// @ts-expect-error: Property 'y' is missing in type '{ x: number; }' but required in type 'Pick<TPoint, "x" | "y">'.(2345)
foo('Y', { x: 1 });

foo('Y', { x: 1, y: 2 });

πŸ’» Use Cases

  1. What do you want to use this for?
    When I have a function where the type of two parameters depend on each other.

  2. What shortcomings exist with current approaches?
    Using a combination of generics and conditional types, we are able to give the function a very nice type signature from the outside, but within the body of the function, the types are practically unusable.

  3. What workarounds are you using in the meantime?
    // @ts-ignore everywhere
    Alternatively wrap the parameters of the function in a single object payload

@xiBread
Copy link

xiBread commented Jul 16, 2024

Duplicate of #50371

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Jul 17, 2024
@typescript-bot
Copy link
Collaborator

This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants