Skip to content

Support for switch statement shorthand #61038

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

Closed
6 tasks done
Arctomachine opened this issue Jan 24, 2025 · 4 comments
Closed
6 tasks done

Support for switch statement shorthand #61038

Arctomachine opened this issue Jan 24, 2025 · 4 comments
Labels
Suggestion An idea for TypeScript Too Complex An issue which adding support for may be too complex for the value it adds

Comments

@Arctomachine
Copy link

πŸ” Search Terms

"switch shorthand"

βœ… Viability Checklist

⭐ Suggestion

Support for type narrowing in

const result = {
  1: checkThis.one
  2: checkThis.two
} [checkThis.number] || checkThis.more

πŸ“ƒ Motivating Example

Imagine you need to narrow type of object from 2 possible options and access property based on that type. Easy solution - ternary.
Now another option is added. Easy solution - extend ternary by another check.
And few more options are added. Extending ternary any more will make it hard to read. Switch statement is easier to read, but it requires to declare variable first and then assign something to it based on condition.
But shorthand switch exists, similar to ternary. And it is not working with typescript.

Playground link or as code:

type Fruits = {
  plantType: "fruit";
  fruitList: string[];
};

type Vegetables = {
  plantType: "vegetable";
  vegetableList: string[];
};

type Berries = {
  plantType: "berry";
  berryList: string[];
};

type Plants = Fruits | Vegetables | Berries;

const testPlant = {
  plantType: "fruit",
  fruitList: [],
} as unknown as Plants;

const selectedListError = {
  fruit: testPlant.fruitList,
  vegetable: testPlant.vegetableList,
  berry: testPlant.berryList,
}[testPlant.plantType];

const selectedListWorks =
  testPlant.plantType === "fruit"
    ? testPlant.fruitList
    : testPlant.plantType === "vegetable"
    ? testPlant.vegetableList
    : testPlant.berryList;
    Property 'fruitList' does not exist on type 'Plants'.
      Property 'fruitList' does not exist on type 'Vegetables'.
    Property 'vegetableList' does not exist on type 'Plants'.
      Property 'vegetableList' does not exist on type 'Fruits'.
    Property 'berryList' does not exist on type 'Plants'.
      Property 'berryList' does not exist on type 'Fruits'.

πŸ’» Use Cases

Main use case: one line switch statement.
Two workarounds: normal switch or long ternary.

@nmain
Copy link

nmain commented Jan 24, 2025

It's not quite like a switch though, is it? In particular, all branches are executed because the whole object literal is evaluated before an individual property is plucked. So there's no narrowing Typescript can do here.

Playground

@jcalz
Copy link
Contributor

jcalz commented Jan 24, 2025

Right, if you want this to actually be a switch-substitute then you need to use something like

function h(u: U): number {
  const o = {
    a(u: A) { return u.a.value },
    b(u: B) { return u.b.value }
  }
  return o[u.type](u); // error!
}

which probably isn't "shorthand" anymore, and effectively reduces this feature request to #30581, the solution to which is #47109, refactor to generics like

interface TypeMap {
  a: { a: { value: number } },
  b: { b: { value: number } }
}
type U<K extends keyof TypeMap = keyof TypeMap> =
  { [P in K]: { type: P } & TypeMap[P] }[K]

function h<K extends keyof TypeMap>(u: U<K>): number {
  const o: { [P in keyof TypeMap]: (u: U<P>) => number } = {
    a(u) { return u.a.value },
    b(u) { return u.b.value }
  }
  return o[u.type](u); // okay
}

and that's not pretty or anything, so I could imagine wanting something more convenient if this pattern were widely used, and... well, this is the first I've seen of it.

@RyanCavanaugh
Copy link
Member

This falls apart as a "switch" replacement as soon as the code gets even modestly more complex, e.g. this code always crashes:

const selectedListError = {
  fruit: testPlant.fruitList.slice(2),
  vegetable: testPlant.vegetableList.slice(1),
  berry: testPlant.berryList,
}[testPlant.plantType];

I don't think it's worth adding a new kind of narrowing to support this

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Too Complex An issue which adding support for may be too complex for the value it adds labels Jan 24, 2025
@typescript-bot
Copy link
Collaborator

This issue has been marked as "Too Complex" 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 Jan 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Suggestion An idea for TypeScript Too Complex An issue which adding support for may be too complex for the value it adds
Projects
None yet
Development

No branches or pull requests

5 participants