From 38f269b92c1c8e92accc4534cc99bdb0da571142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Tranta?= Date: Thu, 6 Feb 2025 16:38:21 +0100 Subject: [PATCH] chore(suite): improve the typing of the pickAndPrepareFrameProps() and fix type / code error --- .../components/src/components/Icon/Icon.tsx | 2 +- .../components/src/utils/frameProps.test.ts | 59 +++++++++++++++++++ packages/components/src/utils/frameProps.tsx | 24 ++++---- .../src/utils/transientProps.test.ts | 28 +++++++++ 4 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 packages/components/src/utils/frameProps.test.ts create mode 100644 packages/components/src/utils/transientProps.test.ts diff --git a/packages/components/src/components/Icon/Icon.tsx b/packages/components/src/components/Icon/Icon.tsx index dd1f6a44e9f..a2c8466b1fe 100644 --- a/packages/components/src/components/Icon/Icon.tsx +++ b/packages/components/src/components/Icon/Icon.tsx @@ -185,8 +185,8 @@ export const Icon = forwardRef( onClick={onClick ? handleClick : undefined} className={className} ref={ref} - $cursor={cursor ?? (onClick ? 'pointer' : undefined)} {...frameProps} + $cursor={cursor ?? (onClick ? 'pointer' : undefined)} > { + describe('type tests', () => { + it('should return the same keys just with the $ prefix as type', () => { + const result: { + $a: 1; + $b: 2; + } = makePropsTransient({ a: 1, b: 2 } as const); + expect(result).toEqual({ + $a: 1, + $b: 2, + }); + }); + + it('should correctly be able to pick individual key', () => { + const result: { + $a: 1; + $b: 2; + } = makePropsTransient({ a: 1, b: 2 } as const); + + const a = result.$a; + expect(a).toEqual(1); + }); + + it('should throw a type error when the resulting object is not assigned to a variable with a $ prefix', () => { + // @ts-expect-error: here should be $ prefix for the key + const result: { + a: 1; + $b: 2; + } = makePropsTransient({ a: 1, b: 2 } as const); + expect(result).toEqual({ + $a: 1, + $b: 2, + }); + }); + it('should throw a type error when trying to get the key that is not specified in the argument object', () => { + // @ts-expect-error: c is not a key of the object + const result: { + $c: 1; + } = makePropsTransient({ a: 1, b: 2 } as const); + expect(result).toEqual({ + $a: 1, + $b: 2, + }); + }); + + it('should throw a type error when trying to access a key without a $ prefix', () => { + const result: { + $a: 1; + $b: 2; + } = makePropsTransient({ a: 1, b: 2 } as const); + + // @ts-expect-error: here should be $ prefix for the key + const { a } = result; + expect(a).toEqual(undefined); + }); + }); +}); diff --git a/packages/components/src/utils/frameProps.tsx b/packages/components/src/utils/frameProps.tsx index d00af81425e..398b835f022 100644 --- a/packages/components/src/utils/frameProps.tsx +++ b/packages/components/src/utils/frameProps.tsx @@ -56,7 +56,7 @@ type Position = { left?: string | number; }; -const cursors = ['pointer', 'help', 'default', 'not-allowed'] as const; +const cursors = ['pointer', 'help', 'default', 'not-allowed', 'inherit'] as const; type Cursor = (typeof cursors)[number]; export type FrameProps = { @@ -83,21 +83,21 @@ type TransientFrameProps = TransientProps; const getValueWithUnit = (value: string | number) => typeof value === 'number' ? `${value}px` : value; -export const pickAndPrepareFrameProps = ( - props: Record, - allowedFrameProps: Array, - convertToTransient = true, +export const pickAndPrepareFrameProps = < + TProps extends { [K in FramePropsKeys]?: FrameProps[K] }, + KFP extends FramePropsKeys[], +>( + props: TProps, + allowedFrameProps: KFP, ) => { - const selectedProps = allowedFrameProps.reduce( + const selectedProps = allowedFrameProps.reduce<{ + [value in KFP[number]]: TProps[value]; + }>( (acc, item) => ({ ...acc, [item]: props[item] }), - {}, + {} as { [value in KFP[number]]: TProps[value] }, ); - if (convertToTransient) { - return makePropsTransient(selectedProps); - } - - return selectedProps; + return makePropsTransient(selectedProps); }; export const withFrameProps = ({ diff --git a/packages/components/src/utils/transientProps.test.ts b/packages/components/src/utils/transientProps.test.ts new file mode 100644 index 00000000000..a814ccd3c48 --- /dev/null +++ b/packages/components/src/utils/transientProps.test.ts @@ -0,0 +1,28 @@ +import { makePropsTransient } from './transientProps'; + +describe('transientProps', () => { + describe('type tests', () => { + it('should return the same keys just with the $ prefix as type', () => { + const result: { + $a: 1; + $b: 2; + } = makePropsTransient({ a: 1, b: 2 } as const); + expect(result).toEqual({ + $a: 1, + $b: 2, + }); + }); + + it("should should throw an a type error when there isn't a property with a $ prefix", () => { + // @ts-expect-error: here should be $ prefixes for the keys + const result: { + a: 1; + b: 2; + } = makePropsTransient({ a: 1, b: 2 } as const); + expect(result).toEqual({ + $a: 1, + $b: 2, + }); + }); + }); +});