mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Remove duplication from exhaustiveness checks for discriminating unions
Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
497ab273ae
commit
1a5073caad
@ -5,3 +5,13 @@
|
|||||||
|
|
||||||
// See: https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions
|
// See: https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions
|
||||||
export interface Discriminable<T extends string> { kind: T }
|
export interface Discriminable<T extends string> { kind: T }
|
||||||
|
|
||||||
|
// Note: this will fail at transpilation time, if all kinds are not instructed in switch/case.
|
||||||
|
// See: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#exhaustiveness-checking
|
||||||
|
export const checkThatAllDiscriminablesAreExhausted = <T extends never>(value: T) => {
|
||||||
|
const _exhaustiveCheck: never = value;
|
||||||
|
|
||||||
|
return new Error(
|
||||||
|
`Tried to exhaust discriminables, but no instructions were found for ${(_exhaustiveCheck as any).kind}`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import type { ApplicationMenuItemTypes } from "./menu-items/application-menu-ite
|
|||||||
import { pipeline } from "@ogre-tools/fp";
|
import { pipeline } from "@ogre-tools/fp";
|
||||||
import { map, sortBy } from "lodash/fp";
|
import { map, sortBy } from "lodash/fp";
|
||||||
import type { MenuItemRoot } from "./application-menu-item-composite.injectable";
|
import type { MenuItemRoot } from "./application-menu-item-composite.injectable";
|
||||||
|
import { checkThatAllDiscriminablesAreExhausted } from "../../../common/utils/composable-responsibilities/discriminable/discriminable";
|
||||||
|
|
||||||
const populateApplicationMenuInjectable = getInjectable({
|
const populateApplicationMenuInjectable = getInjectable({
|
||||||
id: "populate-application-menu",
|
id: "populate-application-menu",
|
||||||
@ -32,12 +33,12 @@ export default populateApplicationMenuInjectable;
|
|||||||
const toHierarchicalElectronMenuItem = (
|
const toHierarchicalElectronMenuItem = (
|
||||||
composite: Composite<ApplicationMenuItemTypes>,
|
composite: Composite<ApplicationMenuItemTypes>,
|
||||||
): MenuItemOpts => {
|
): MenuItemOpts => {
|
||||||
switch (composite.value.kind) {
|
const value = composite.value;
|
||||||
|
|
||||||
|
switch (value.kind) {
|
||||||
case "top-level-menu": {
|
case "top-level-menu": {
|
||||||
const {
|
const { id } = composite;
|
||||||
id,
|
const { label, role } = value;
|
||||||
value: { label, role },
|
|
||||||
} = composite;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...(id ? { id } : {}),
|
...(id ? { id } : {}),
|
||||||
@ -53,10 +54,8 @@ const toHierarchicalElectronMenuItem = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "sub-menu": {
|
case "sub-menu": {
|
||||||
const {
|
const { id } = composite;
|
||||||
id,
|
const { label } = value;
|
||||||
value: { label },
|
|
||||||
} = composite;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...(id ? { id } : {}),
|
...(id ? { id } : {}),
|
||||||
@ -71,10 +70,8 @@ const toHierarchicalElectronMenuItem = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "clickable-menu-item": {
|
case "clickable-menu-item": {
|
||||||
const {
|
const { id } = composite;
|
||||||
id,
|
const { label, onClick, keyboardShortcut } = value;
|
||||||
value: { label, onClick, keyboardShortcut },
|
|
||||||
} = composite;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...(id ? { id } : {}),
|
...(id ? { id } : {}),
|
||||||
@ -85,9 +82,7 @@ const toHierarchicalElectronMenuItem = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "os-action-menu-item": {
|
case "os-action-menu-item": {
|
||||||
const {
|
const { label, keyboardShortcut, actionName } = value;
|
||||||
value: { label, keyboardShortcut, actionName },
|
|
||||||
} = composite;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...(label ? { label } : {}),
|
...(label ? { label } : {}),
|
||||||
@ -103,14 +98,7 @@ const toHierarchicalElectronMenuItem = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
// Note: this will fail at transpilation time, if all ApplicationMenuItemTypes
|
throw checkThatAllDiscriminablesAreExhausted(value);
|
||||||
// are not handled in switch/case.
|
|
||||||
const _exhaustiveCheck: never = composite.value;
|
|
||||||
|
|
||||||
// Note: this code is unreachable, it is here to make ts not complain about
|
|
||||||
// _exhaustiveCheck not being used.
|
|
||||||
// See: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#exhaustiveness-checking
|
|
||||||
throw new Error(`Tried to create application menu, but foreign menu item was encountered: ${_exhaustiveCheck} ${composite.value}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import { PreferencesNavigationTab } from "./preferences-navigation-tab";
|
|||||||
import { compositeHasDescendant } from "../../../../common/utils/composite/composite-has-descendant/composite-has-descendant";
|
import { compositeHasDescendant } from "../../../../common/utils/composite/composite-has-descendant/composite-has-descendant";
|
||||||
import type { PreferenceTabsRoot } from "../preference-items/preference-tab-root";
|
import type { PreferenceTabsRoot } from "../preference-items/preference-tab-root";
|
||||||
import { Icon } from "../../../../renderer/components/icon";
|
import { Icon } from "../../../../renderer/components/icon";
|
||||||
|
import { checkThatAllDiscriminablesAreExhausted } from "../../../../common/utils/composable-responsibilities/discriminable/discriminable";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
composite: IComputedValue<Composite<PreferenceTypes | PreferenceTabsRoot>>;
|
composite: IComputedValue<Composite<PreferenceTypes | PreferenceTabsRoot>>;
|
||||||
@ -88,16 +89,7 @@ const toNavigationHierarchy = (composite: Composite<PreferenceTypes | Preference
|
|||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
// Note: this will fail at transpilation time, if all kinds
|
throw checkThatAllDiscriminablesAreExhausted(value);
|
||||||
// are not handled in switch/case.
|
|
||||||
const _exhaustiveCheck: never = value;
|
|
||||||
|
|
||||||
// Note: this code is unreachable, it is here to make ts not complain about
|
|
||||||
// _exhaustiveCheck not being used.
|
|
||||||
// See: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#exhaustiveness-checking
|
|
||||||
throw new Error(
|
|
||||||
`Tried to create preference navigation, but foreign item was encountered: ${_exhaustiveCheck} ${composite.value}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -108,3 +100,4 @@ const hasContent = compositeHasDescendant<PreferenceTypes | PreferenceTabsRoot>(
|
|||||||
|
|
||||||
const emptyRender = <></>;
|
const emptyRender = <></>;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { Map } from "../../../renderer/components/map/map";
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { PreferencesNavigation } from "./preference-navigation/preferences-navigation";
|
import { PreferencesNavigation } from "./preference-navigation/preferences-navigation";
|
||||||
import Gutter from "../../../renderer/components/gutter/gutter";
|
import Gutter from "../../../renderer/components/gutter/gutter";
|
||||||
|
import { checkThatAllDiscriminablesAreExhausted } from "../../../common/utils/composable-responsibilities/discriminable/discriminable";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
closePreferences: () => void;
|
closePreferences: () => void;
|
||||||
@ -94,16 +95,7 @@ const toPreferenceItemHierarchy = (composite: Composite<PreferenceTypes>) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
// Note: this will fail at transpilation time, if all kinds
|
throw checkThatAllDiscriminablesAreExhausted(value);
|
||||||
// are not handled in switch/case.
|
|
||||||
const _exhaustiveCheck: never = value;
|
|
||||||
|
|
||||||
// Note: this code is unreachable, it is here to make ts not complain about
|
|
||||||
// _exhaustiveCheck not being used.
|
|
||||||
// See: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#exhaustiveness-checking
|
|
||||||
throw new Error(
|
|
||||||
`Tried to create preferences, but foreign item was encountered: ${_exhaustiveCheck} ${value}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user