chore: fix various lint/type issues found by oxlint (#2850)

This commit is contained in:
Braden MacDonald
2026-01-30 17:01:11 -08:00
committed by GitHub
parent b0066e547c
commit 6effb4d39e
36 changed files with 120 additions and 78 deletions

View File

@@ -1,3 +1,4 @@
// oxlint-disable unicorn/no-thenable
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { camelCase } from 'lodash';

View File

@@ -28,6 +28,10 @@ const renderComponent = children => (
let axiosMock;
describe('ProctoredExamSettings', () => {
/**
* @param {boolean} isAdmin
* @param {string | undefined} org
*/
function setupApp(isAdmin = true, org = undefined) {
mergeConfig({
EXAMS_BASE_URL: 'http://exams.testing.co',

View File

@@ -107,6 +107,7 @@ const TeamSettings = ({
)
.when('enabled', {
is: true,
// oxlint-disable-next-line unicorn/no-thenable
then: Yup.array().min(1),
})
.default([])

View File

@@ -25,7 +25,7 @@ export function fetchCourseAppSettings(courseId) {
sortedDisplayName.push(displayName);
});
const sortedSettingValues = {};
sortedDisplayName.sort().forEach((displayName => {
sortedDisplayName.sort((a, b) => a.localeCompare(b)).forEach((displayName => {
Object.entries(settingValues).forEach(([key, value]) => {
if (value.displayName === displayName) {
sortedSettingValues[key] = value;

View File

@@ -7,7 +7,7 @@ const CertificateSection = ({
<section {...rest}>
<Stack className="justify-content-between mb-2.5" direction="horizontal">
<h2 className="lead section-title mb-0">{title}</h2>
{actions && actions}
{actions}
</Stack>
<hr className="mt-0 mb-4" />
<div>

View File

@@ -9,14 +9,14 @@ import {
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { getItemIcon } from '@src/generic/block-type-utils';
import { ContainerType } from '@src/generic/key-utils';
import { COMPONENT_TYPES } from '@src/generic/block-type-utils/constants';
import messages from './messages';
import { ContainerState } from './types';
import { isRowClickable } from './utils';
export interface ContainerRowProps {
title: string;
containerType: ContainerType | keyof typeof COMPONENT_TYPES | string;
/** containerType: can be one of `ContainerType` | `COMPONENT_TYPES` or any other string (3rd party XBlocks) */
containerType: ContainerType | string;
state?: ContainerState;
side: 'Before' | 'After';
originalName?: string;

View File

@@ -128,6 +128,7 @@ export function diffPreviewContainerChildren<A extends CourseContainerChildBase,
// Use new mapB for getting new index for added elements
addedA.forEach((addedRow) => {
// oxlint-disable-next-line typescript/no-non-null-asserted-optional-chain FIXME: clean this up.
updatedA.splice(mapB.get(addedRow.id)?.index!, 0, { ...addedRow, state: 'added' });
});

View File

@@ -75,11 +75,17 @@ const TagComponent = ({
};
interface TagsTreeProps {
/** Array of taxonomy tags that are applied to the content. */
tags: TagTree;
/** Key of the parent tag. */
parentKey?: string;
/** Depth of the parent tag (root), used to render tabs for the tree. */
rootDepth?: number;
/** Lineage of the tag. */
lineage?: string[];
/** Function that is called when removing tags from the tree. */
removeTagHandler?: (value: string) => void;
/** Optional component to render after the tags components. */
afterTagsComponent?: React.ReactNode;
}
@@ -121,17 +127,12 @@ interface TagsTreeProps {
*
*/
const TagsTree = ({
/** Array of taxonomy tags that are applied to the content. */
tags,
/** Depth of the parent tag (root), used to render tabs for the tree. */
rootDepth = 0,
/** Key of the parent tag. */
parentKey,
/** Lineage of the tag. */
lineage = [],
/** Function that is called when removing tags from the tree. */
removeTagHandler,
/** Optional component to render after the tags components. */
// oxlint-disable-next-line oxc/only-used-in-recursion
afterTagsComponent,
}: TagsTreeProps) => {
const { isEditMode } = useContext(ContentTagsDrawerContext);

View File

@@ -10,14 +10,13 @@ export interface CourseStructure {
hasChanges: boolean,
}
// TODO: Create interface for all `Object` fields in courseOutline
export interface CourseOutline {
courseReleaseDate: string;
courseStructure: CourseStructure;
deprecatedBlocksInfo: Object;
deprecatedBlocksInfo: Record<string, any>; // TODO: Create interface for this type
discussionsIncontextLearnmoreUrl: string;
initialState: Object;
initialUserClipboard: Object;
initialState: Record<string, any>; // TODO: Create interface for this type
initialUserClipboard: Record<string, any>; // TODO: Create interface for this type
languageCode: string;
lmsLink: string;
mfeProctoredExamSettingsUrl: string;

View File

@@ -70,9 +70,7 @@ const searchResult = {
results: [
{
...mockResult.results[0],
hits: [
...mockResult.results[0].hits.slice(16, 19),
],
hits: mockResult.results[0].hits.slice(16, 19),
},
{
...mockResult.results[1],

View File

@@ -90,6 +90,7 @@ const AddContentButton = ({ name, blockType } : AddContentButtonProps) => {
break;
default:
// istanbul ignore next: unreachable
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
throw new Error(`Unrecognized block type ${blockType}`);
}
stopCurrentFlow();

View File

@@ -92,7 +92,7 @@ export const LegacyStatusBar = ({
>
{courseReleaseDateObj.isValid() ? (
<FormattedDate
value={courseReleaseDateObj.toString()}
value={courseReleaseDateObj.toISOString()}
year="numeric"
month="short"
day="2-digit"

View File

@@ -110,7 +110,7 @@ const CourseDates = ({
<Stack direction="horizontal" gap={2}>
<Icon size="sm" className="mb-1" src={Event} />
<FormattedDate
value={startDate.toString()}
value={startDate.toISOString()}
year="numeric"
month="short"
day="2-digit"
@@ -119,7 +119,7 @@ const CourseDates = ({
<>
{' - '}
<FormattedDate
value={endDate.toString()}
value={endDate.toISOString()}
year="numeric"
month="short"
day="2-digit"

View File

@@ -36,7 +36,7 @@ const ReleaseStatus = ({
</span>
<Icon className="mr-1" size="sm" src={ClockIcon} />
{intl.formatMessage(releaseLabel)}
{releaseDate && releaseDate}
{releaseDate}
</div>
);

View File

@@ -1,3 +1,4 @@
// oxlint-disable unicorn/no-useless-spread
/* eslint-disable react/prop-types */
import userEvent from '@testing-library/user-event';

View File

@@ -23,7 +23,9 @@ const ReleaseInfoComponent = () => {
);
}
return releaseInfo.message;
// istanbul ignore next
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{releaseInfo.message}</>;
};
export default ReleaseInfoComponent;

View File

@@ -29,6 +29,16 @@ const messages = defineMessages({
id: 'course-authoring.course-unit.sidebar.body.note',
defaultMessage: 'Note: Do not hide graded assignments after they have been released.',
},
publishInfoDraftSaved: {
id: 'course-authoring.course-unit.publish.info.draft.saved',
defaultMessage: 'DRAFT SAVED',
description: 'Label for the draft date in the publish info section',
},
publishLastPublished: {
id: 'course-authoring.course-unit.publish.info.last.published',
defaultMessage: 'LAST PUBLISHED',
description: 'Label for the last published date in the publish info section',
},
publishInfoPreviouslyPublished: {
id: 'course-authoring.course-unit.publish.info.previously-published',
defaultMessage: 'Previously published',

View File

@@ -5,20 +5,32 @@ import {
Lock,
} from '@openedx/paragon/icons';
import type { IntlShape } from 'react-intl';
import { ICON_COLOR_VARIANTS, UNIT_VISIBILITY_STATES } from '../constants';
import messages from './messages';
/**
* Get information about the publishing status.
* @param {Object} intl - The internationalization object.
* @param {boolean} hasChanges - Indicates if there are unpublished changes.
* @param {string} editedBy - The user who edited the content.
* @param {string} editedOn - The timestamp when the content was edited.
* @param {string} publishedBy - The user who last published the content.
* @param {string} publishedOn - The timestamp when the content was last published.
* @returns {string} Publish information based on the provided parameters.
* @param intl - The internationalization object.
* @param hasChanges - Indicates if there are unpublished changes.
* @param editedBy - The user who edited the content.
* @param editedOn - The timestamp when the content was edited.
* @param publishedBy - The user who last published the content.
* @param publishedOn - The timestamp when the content was last published.
* @returns Publish information based on the provided parameters.
*/
export const getPublishInfo = (intl, hasChanges, editedBy, editedOn, publishedBy, publishedOn) => {
// this fn appears to be unused - <SidebarBody> is never called with displayUnitLocation=false.
// Ingoring it for coverage for now and we'll delete the whole legacy sidebar soon.
// istanbul ignore next
export const getPublishInfo = (
intl: IntlShape,
hasChanges: boolean,
editedBy: string,
editedOn: string,
publishedBy: string,
publishedOn: any,
): string => {
let publishInfoText;
if (hasChanges && editedOn && editedBy) {
publishInfoText = intl.formatMessage(messages.publishInfoDraftSaved, { editedOn, editedBy });
@@ -33,12 +45,12 @@ export const getPublishInfo = (intl, hasChanges, editedBy, editedOn, publishedBy
/**
* Get information about the release status.
* @param {Object} intl - The internationalization object.
* @param {string} releaseDate - The release date of the content.
* @param {string} releaseDateFrom - The section name associated with the release date.
* @returns {string|ReactElement} Release information based on the provided parameters.
* @param intl - The internationalization object.
* @param releaseDate - The release date of the content.
* @param releaseDateFrom - The section name associated with the release date.
* @returns Release information based on the provided parameters.
*/
export const getReleaseInfo = (intl, releaseDate, releaseDateFrom) => {
export const getReleaseInfo = (intl: IntlShape, releaseDate: string, releaseDateFrom: string) => {
if (releaseDate) {
return {
isScheduled: true,
@@ -55,14 +67,14 @@ export const getReleaseInfo = (intl, releaseDate, releaseDateFrom) => {
/**
* Get the icon variant based on the provided visibility state and publication status.
* @param {string} visibilityState - The visibility state of the content.
* @param {boolean} published - Indicates if the content is published.
* @param {boolean} hasChanges - Indicates if there are unpublished changes.
* @returns {Object} An object containing the icon component and color variant.
* @param visibilityState - The visibility state of the content.
* @param published - Indicates if the content is published.
* @param hasChanges - Indicates if there are unpublished changes.
* @returns An object containing the icon component and color variant.
* - iconSrc: The source component for the icon.
* - colorVariant: The color variant for the icon.
*/
export const getIconVariant = (visibilityState, published, hasChanges) => {
export const getIconVariant = (visibilityState: string, published: boolean, hasChanges: boolean) => {
const iconVariants = {
[UNIT_VISIBILITY_STATES.staffOnly]: { iconSrc: Lock, colorVariant: ICON_COLOR_VARIANTS.PRIMARY },
[UNIT_VISIBILITY_STATES.live]: { iconSrc: CheckCircleIcon, colorVariant: ICON_COLOR_VARIANTS.GREEN },
@@ -81,7 +93,7 @@ export const getIconVariant = (visibilityState, published, hasChanges) => {
/**
* Extracts the clear course unit ID from the given course unit data.
* @param {string} id - The course unit ID.
* @returns {string} The clear course unit ID extracted from the provided data.
* @param id - The course unit ID.
* @returns The clear course unit ID extracted from the provided data.
*/
export const extractCourseUnitId = (id) => id.match(/block@(.+)$/)[1];
export const extractCourseUnitId = (id: string): string => id.match(/block@(.+)$/)![1];

View File

@@ -27,7 +27,7 @@ const courseId = '1234567890';
const closeModalMockFn = jest.fn() as jest.MockedFunction<() => void>;
const openModalMockFn = jest.fn() as jest.MockedFunction<() => void>;
const scrollToMockFn = jest.fn() as jest.MockedFunction<() => void>;
const sections: IXBlock[] | any = camelCaseObject(courseOutlineInfoMock)?.childInfo.children || [];
const sections: IXBlock[] = camelCaseObject(courseOutlineInfoMock)?.childInfo.children || [];
const subsections: IXBlock[] = sections[1]?.childInfo?.children || [];
const units: IXBlock[] = subsections[1]?.childInfo?.children || [];
const components: IXBlock[] = units[0]?.childInfo?.children || [];

View File

@@ -85,7 +85,7 @@ const UnitInfoSettings = () => {
const handleUpdate = async (
isVisible: boolean,
groupAccess: Object | null,
groupAccess: Record<string, any> | null,
isDiscussionEnabled: boolean,
) => {
// oxlint-disable-next-line @typescript-eslint/await-thenable - this dispatch() IS returning a promise.

View File

@@ -88,7 +88,7 @@ export const useVideoListProps = ({
videos,
returnFunction,
}) => {
const [highlighted, setHighlighted] = React.useState(null);
const [highlighted, setHighlighted] = React.useState(/** @type {string | null} */(null));
const [
showSelectVideoError,
setShowSelectVideoError,

View File

@@ -122,7 +122,7 @@ export interface EditorState {
videoSharingEnabledForAll: boolean;
videoSharingEnabledForCourse: boolean;
videoSharingLearnMoreLink: string;
thumbnail: null | any;
thumbnail: any;
transcripts: any[];
selectedVideoTranscriptUrls: Record<string, any>;
allowTranscriptDownloads: boolean;
@@ -172,7 +172,7 @@ export interface EditorState {
additionalAttributes: Record<string, any>;
defaultSettings: Record<string, any>;
settings: {
randomization: null | any; // Not sure what type this field has
randomization: any; // Not sure what type this field has
scoring: {
weight: number;
attempts: { unlimited: boolean; number: number | null; };

View File

@@ -59,8 +59,8 @@ export const networkRequest = ({
/**
* Tracked fetchByBlockId api method.
* Tracked to the `fetchBlock` request key.
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
* @param {[func]} onFailure - onFailure method ((error) => { ... })
* @param {func} onSuccess - onSuccess method ((response) => { ... })
* @param {func} onFailure - onFailure method ((error) => { ... })
*/
export const fetchBlock = ({ ...rest }) => (dispatch, getState) => {
dispatch(module.networkRequest({
@@ -77,8 +77,8 @@ export const fetchBlock = ({ ...rest }) => (dispatch, getState) => {
* Tracked fetchStudioView api method.
* Tracked to the `fetchBlock` request key.
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
* @param {[func]} onFailure - onFailure method ((error) => { ... })
* @param {func} onSuccess - onSuccess method ((response) => { ... })
* @param {func} onFailure - onFailure method ((error) => { ... })
*/
export const fetchStudioView = ({ ...rest }) => (dispatch, getState) => {
dispatch(module.networkRequest({
@@ -94,8 +94,8 @@ export const fetchStudioView = ({ ...rest }) => (dispatch, getState) => {
/**
* Tracked fetchByUnitId api method.
* Tracked to the `fetchUnit` request key.
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
* @param {[func]} onFailure - onFailure method ((error) => { ... })
* @param {func} onSuccess - onSuccess method ((response) => { ... })
* @param {func} onFailure - onFailure method ((error) => { ... })
*/
export const fetchUnit = ({ ...rest }) => (dispatch, getState) => {
dispatch(module.networkRequest({
@@ -111,8 +111,8 @@ export const fetchUnit = ({ ...rest }) => (dispatch, getState) => {
/**
* Tracked saveBlock api method. Tracked to the `saveBlock` request key.
* @param {Object} content
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
* @param {[func]} onFailure - onFailure method ((error) => { ... })
* @param {func} onSuccess - onSuccess method ((response) => { ... })
* @param {func} onFailure - onFailure method ((error) => { ... })
*/
export const saveBlock = ({ content, ...rest }) => (dispatch, getState) => {
dispatch(module.networkRequest({
@@ -131,8 +131,8 @@ export const saveBlock = ({ content, ...rest }) => (dispatch, getState) => {
/**
* Tracked createBlock api method. Tracked to the `createBlock` request key.
* @param {[func]} onSuccess - onSuccess method ((response) => { ... })
* @param {[func]} onFailure - onFailure method ((error) => { ... })
* @param {func} onSuccess - onSuccess method ((response) => { ... })
* @param {func} onFailure - onFailure method ((error) => { ... })
*/
export const createBlock = ({ ...rest }) => (dispatch, getState) => {
const blockTitle = selectors.app.blockTitle(getState());

View File

@@ -78,7 +78,7 @@ describe('CodeEditor', () => {
});
describe('textArr is undefined', () => {
it('returns empty array', () => {
let textArr;
const textArr = undefined;
const diagnostics = hooks.syntaxChecker({ textArr, lang: 'html' });
expect(diagnostics).toEqual([]);
});

View File

@@ -15,7 +15,7 @@ export const getCourseVideosApiUrl = (courseId) => `${getApiBaseUrl()}/videos/${
/**
* Fetches the course custom pages for provided course
* @param {string} courseId
* @returns {Promise<[{}]>}
* @returns {Promise<Record<string, any>>}
*/
export async function getVideos(courseId) {
const { data } = await getAuthenticatedHttpClient()

View File

@@ -82,7 +82,7 @@ export const getSortedTranscripts = (languages, transcripts) => {
transcriptDisplayNames.push(displayName);
});
const sortedTranscripts = transcriptDisplayNames.sort();
const sortedTranscripts = transcriptDisplayNames.sort((a, b) => a.localeCompare(b));
const sortedTranscriptCodes = [];
sortedTranscripts.forEach(transcript => {
Object.entries(languages).forEach(([key, value]) => {

View File

@@ -12,6 +12,8 @@ interface Props {
value: string | number;
}
// Because <Form.Control> is only typed as 'any' in Paragon so far, the props of the following become 'any' :/
// oxlint-disable-next-line @typescript-eslint(no-redundant-type-constituents
const FormikControl: React.FC<Props & React.ComponentProps<typeof Form.Control>> = ({
name,
// eslint-disable-next-line react/jsx-no-useless-fragment

View File

@@ -41,7 +41,7 @@ export async function getCourseRerun(courseId: string): Promise<unknown> {
/**
* Create or rerun course with data.
*/
export async function createOrRerunCourse(courseData: Object): Promise<unknown> {
export async function createOrRerunCourse(courseData: Record<string, any>): Promise<unknown> {
const { data } = await getAuthenticatedHttpClient().post(
getCreateOrRerunCourseUrl(),
convertObjectToSnakeCase(courseData, true),

View File

@@ -79,7 +79,7 @@ export function isLibraryV1Key(learningContextKey: string | undefined | null): l
}
/** Check if this is a V1 block key. */
export function isBlockV1Key(usageKey: string | undefined | null): usageKey is string {
export function isBlockV1Key(usageKey: string | undefined | null): boolean {
return typeof usageKey === 'string' && usageKey.startsWith('block-v1:');
}

View File

@@ -8,9 +8,9 @@ export const getImportStatusApiUrl = (courseId, fileName) => `${getApiBaseUrl()}
/**
* Start import course.
* @param {string} courseId
* @param {Object} fileData
* @param {Object} requestConfig
* @returns {Promise<Object>}
* @param {File} fileData
* @param {Record<string, any>} requestConfig
* @returns {Promise<Record<string, any>>}
*/
export async function startCourseImporting(courseId, fileData, requestConfig, updateProgress) {
const chunkSize = 20 * 1000000; // 20 MB

View File

@@ -397,15 +397,16 @@ const AddContent = () => {
// Include the 'Paste from Clipboard' button if there is an Xblock in the clipboard
// that can be pasted
const showPasteButton = false
const showPasteButton = (
// We are not in a unit, subsection, or section, so we can paste any XBlock
|| (!(insideUnit || insideSubsection || insideSection) && isPasteable)
(!(insideUnit || insideSubsection || insideSection) && isPasteable)
// We are in a unit, so we can paste only components
|| (insideUnit && showPasteXBlock)
// We are in a subsection, so we can only paste units
|| (insideSubsection && showPasteUnit)
// We are in a section, so we can only paste subsections
|| (insideSection && showPasteSubsection);
|| (insideSection && showPasteSubsection)
);
if (showPasteButton) {
const pasteButton = {

View File

@@ -28,12 +28,13 @@ interface DisplayNumberComponentProps {
count?: string;
isPending?: boolean;
icon?: React.ComponentType;
title?: MessageDescriptor;
typeId: 'total' | 'section' | 'subsection' | 'unit' | 'unsupported';
title: MessageDescriptor;
info?: React.ReactNode;
}
const DisplayNumberComponent = ({
count, isPending, icon, title, info,
count, isPending, icon, typeId, title, info,
}: DisplayNumberComponentProps) => (
<>
<div className="d-flex align-items-start">
@@ -43,7 +44,7 @@ const DisplayNumberComponent = ({
<OverlayTrigger
placement="top"
overlay={(
<Tooltip variant="light" id={`${title}-info`}>
<Tooltip variant="light" id={`${typeId}-info`}>
{info}
</Tooltip>
)}
@@ -100,6 +101,7 @@ export const SummaryCard = ({
<DisplayNumberComponent
count={totalBlocksStr}
isPending={isPending}
typeId="total"
title={messages.importCourseTotalBlocks}
/>
</Stack>
@@ -107,6 +109,7 @@ export const SummaryCard = ({
<DisplayNumberComponent
count={sections?.toString()}
isPending={isPending}
typeId="section"
icon={getItemIcon('section')}
title={messages.importCourseSections}
/>
@@ -115,6 +118,7 @@ export const SummaryCard = ({
<DisplayNumberComponent
count={subsections?.toString()}
isPending={isPending}
typeId="subsection"
icon={getItemIcon('subsection')}
title={messages.importCourseSubsections}
/>
@@ -123,6 +127,7 @@ export const SummaryCard = ({
<DisplayNumberComponent
count={units?.toString()}
isPending={isPending}
typeId="unit"
icon={getItemIcon('unit')}
title={messages.importCourseUnits}
/>
@@ -132,6 +137,7 @@ export const SummaryCard = ({
count={totalComponentsStr}
isPending={isPending}
icon={Widgets}
typeId="unsupported"
title={messages.importCourseComponents}
info={unsupportedBlocks ? (
<FormattedMessage

View File

@@ -14,7 +14,7 @@ export interface CourseOptimizerState {
loadingStatus: string;
savingStatus: string;
rerunLinkUpdateInProgress: boolean | null;
rerunLinkUpdateResult: any | null;
rerunLinkUpdateResult: any;
}
export type RootState = {

View File

@@ -31,7 +31,7 @@ const OpenedXConfigForm = ({
const appConfigObj = useModel('appConfigs', selectedAppId);
const discussionTopicsModel = useModels('discussionTopics', discussionTopicIds);
const legacyAppConfig = {
...(appConfigObj || {}),
...appConfigObj,
divideDiscussionIds,
enableInContext: true,
enableGradedUnits,
@@ -64,6 +64,7 @@ const OpenedXConfigForm = ({
.required(intl.formatMessage(messages.restrictedEndDateRequired))
.when('startDate', {
is: (startDate) => startDate,
// oxlint-disable-next-line unicorn/no-thenable
then: Yup.string().compare(intl.formatMessage(messages.restrictedEndDateInPast), 'date'),
}),
startTime: Yup.string().checkFormat(
@@ -74,6 +75,7 @@ const OpenedXConfigForm = ({
.checkFormat(intl.formatMessage(messages.restrictedEndTimeInValidFormat), 'time')
.when('startTime', {
is: (startTime) => startTime,
// oxlint-disable-next-line unicorn/no-thenable
then: Yup.string().compare(intl.formatMessage(messages.restrictedEndTimeInPast), 'time'),
}),
}),

View File

@@ -4,7 +4,7 @@ import { LICENSE_TYPE, LICENSE_COMMONS_OPTIONS, creativeCommonsVersion } from '.
import { generateLicenseURL } from './utils';
const useLicenseDetails = (license, onChange) => {
const [licenseType, setLicenseType] = useState(null);
const [licenseType, setLicenseType] = useState(/** @type { string | null } */(null));
const [licenseDetails, setLicenseDetails] = useState({});
const [licenseURL, setLicenseURL] = useState('');

View File

@@ -34,7 +34,7 @@ export function useIsDesktop() {
return useMediaQuery({ query: '(min-width: 992px)' });
}
export function convertObjectToSnakeCase(obj: Object, unpacked = false) {
export function convertObjectToSnakeCase(obj: Record<string, any>, unpacked = false) {
return Object.keys(obj).reduce((snakeCaseObj, key) => {
const snakeCaseKey = snakeCase(key);
const value = unpacked ? obj[key] : { value: obj[key] };
@@ -45,7 +45,7 @@ export function convertObjectToSnakeCase(obj: Object, unpacked = false) {
}, {});
}
export function deepConvertingKeysToCamelCase(obj: any[] | Object | null) {
export function deepConvertingKeysToCamelCase(obj: any[] | Record<string, any> | null) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
@@ -62,7 +62,7 @@ export function deepConvertingKeysToCamelCase(obj: any[] | Object | null) {
return camelCaseObj;
}
export function deepConvertingKeysToSnakeCase(obj: any[] | Object | null) {
export function deepConvertingKeysToSnakeCase(obj: any[] | Record<string, any> | null) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}