Merged in chore/update-eslint-configs (pull request #2812)

chore: Extend eslint configs from @typescript-eslint/recommended

* Change to typescript recommended in scandic-web

* Remove comment

* Change to recommended ts config in partner-sas

* Change to recommended ts lint config in booking-flow


Approved-by: Linus Flood
This commit is contained in:
Anton Gunnarsson
2025-09-17 07:55:11 +00:00
parent e6d5c45ca7
commit 5a86cbaafe
42 changed files with 74 additions and 46 deletions

View File

@@ -9,7 +9,7 @@ import { getLang } from "@/i18n/serverContext"
import { ClientComponent } from "../../../components/ClientComponent"
type SearchParams<S = {}> = {
type SearchParams<S = object> = {
searchParams: Promise<S & { [key: string]: string }>
}

View File

@@ -13,7 +13,7 @@ export default async function PaymentCallbackPage(
logger.debug(`[payment-callback] callback started`)
const lang = params.lang
let userAccessToken = null
const userAccessToken = null
// TODO fix when auth is implemented
// const session = await auth()
// if (isValidSession(session)) {

View File

@@ -29,6 +29,7 @@ export function trackOpenSidePeek(input: {
console.warn("TODO: Implement trackOpenSidePeek", { input })
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function trackGenericEvent(data: any) {
console.warn("TODO: Implement trackGenericEvent", { data })
}

View File

@@ -13,7 +13,10 @@ const compat = new FlatCompat({
export default defineConfig([
{
extends: compat.extends("next/core-web-vitals", "plugin:import/typescript"),
extends: compat.extends(
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended"
),
plugins: {
"simple-import-sort": simpleImportSort,
"@typescript-eslint": typescriptEslint,

View File

@@ -10,7 +10,7 @@ import type { PageArgs } from "@/types/params"
export { generateMetadata } from "@/utils/metadata/generateMetadata"
export default async function DestinationCityPagePage(
props: PageArgs<{}, { view?: "map"; filterFromUrl?: string }>
props: PageArgs<object, { view?: "map"; filterFromUrl?: string }>
) {
const searchParams = await props.searchParams
return (

View File

@@ -10,7 +10,7 @@ import type { PageArgs } from "@/types/params"
export { generateMetadata } from "@/utils/metadata/generateMetadata"
export default async function DestinationCountryPagePage(
props: PageArgs<{}, { view?: "map"; filterFromUrl?: string }>
props: PageArgs<object, { view?: "map"; filterFromUrl?: string }>
) {
const searchParams = await props.searchParams
return (

View File

@@ -13,7 +13,7 @@ import type { PageArgs } from "@/types/params"
export { generateMetadata } from "@/utils/metadata/generateMetadata"
export default async function HotelPagePage(
props: PageArgs<{}, { subpage?: string; view?: "map" }>
props: PageArgs<object, { subpage?: string; view?: "map" }>
) {
const searchParams = await props.searchParams
const hotelPageData = await getHotelPage()

View File

@@ -9,7 +9,7 @@ import type { NextSearchParams, PageArgs } from "@/types/params"
export { generateMetadata } from "@/utils/metadata/generateMetadata"
export default async function StartPagePage(
props: PageArgs<{}, NextSearchParams>
props: PageArgs<object, NextSearchParams>
) {
const searchParams = await props.searchParams
const booking = parseBookingWidgetSearchParams(searchParams)

View File

@@ -119,6 +119,7 @@ export async function GET(
logger.debug(`[login] final redirectUrl: ${redirectTo}`)
/** Record<string, any> is next-auth typings */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const params: Record<string, any> = {
ui_locales: contextParams.lang,
scope: [

View File

@@ -8,7 +8,7 @@ import { getLang } from "@/i18n/serverContext"
import type { NextSearchParams, PageArgs } from "@/types/params"
export default async function BookingWidgetDestinationCityPage(
props: PageArgs<{}, NextSearchParams>
props: PageArgs<object, NextSearchParams>
) {
const searchParams = await props.searchParams

View File

@@ -8,7 +8,7 @@ import { getLang } from "@/i18n/serverContext"
import type { NextSearchParams, PageArgs } from "@/types/params"
export default async function BookingWidgetHotelPage(
props: PageArgs<{}, NextSearchParams & { subpage?: string }>
props: PageArgs<object, NextSearchParams & { subpage?: string }>
) {
const searchParams = await props.searchParams

View File

@@ -29,7 +29,7 @@ export function LinkAccountForm({
}) {
const router = useRouter()
const params = useParams<LangParams>()
let [isPending, startTransition] = useTransition()
const [isPending, startTransition] = useTransition()
const intl = useIntl()
const form = useForm<LinkAccountForm>({
defaultValues: {

View File

@@ -13,7 +13,7 @@ import type {
} from "@/types/params"
export default async function ContentTypePage(
props: PageArgs<LangParams & ContentTypeWebviewParams & UIDParams, {}>
props: PageArgs<LangParams & ContentTypeWebviewParams & UIDParams>
) {
const params = await props.params

View File

@@ -63,7 +63,11 @@ export function getInitialState({
}
}
export function reducer(state: any, action: OverviewTableReducerAction) {
export function reducer(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
state: any,
action: OverviewTableReducerAction
) {
switch (action.type) {
case OverviewTableActionsEnum.SET_SELECTED_LEVEL_A_MOBILE:
return {

View File

@@ -28,6 +28,7 @@ export default function TableBlock({ data }: TableBlockProps) {
accessorKey: col.id,
header: col.header,
size: col.width,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
cell: (info: any) => (
<div dangerouslySetInnerHTML={{ __html: info.getValue() }} />
),

View File

@@ -17,6 +17,7 @@ export default function DialogshiftWidgetClient({
widgetId,
language,
}: DialogshiftWidgetClientProps) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const dialogshiftRef = useRef<any>(null)
useEffect(() => {

View File

@@ -42,6 +42,7 @@ import type { RenderOptions } from "@/types/rte/option"
function extractPossibleAttributes(attrs: Attributes | undefined) {
if (!attrs) return {}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const props: Record<string, any> = {}
if (attrs.id) {
props.id = attrs.id
@@ -601,7 +602,7 @@ export const renderOptions: RenderOptions = {
className?: string,
id?: string
) => {
let props = {
const props = {
className,
id,
}
@@ -614,9 +615,6 @@ export const renderOptions: RenderOptions = {
if (className) {
if (hasAvailableULFormat(className)) {
// @ts-ignore: We want to set css modules classNames even if it does not correspond
// to an existing class in the module style sheet. Due to our css modules plugin for
// typescript, we cannot do this without the ts-ignore
props.className = styles[className]
}
}

View File

@@ -36,6 +36,7 @@ export function nodeChildrenToHtml(
nodes: RTENode[],
embeds: EmbedByUid,
fullRenderOptions: RenderOptions
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): any {
return nodes
.map((node, i) => {

View File

@@ -176,10 +176,7 @@ export default function Form({ user }: EditFormProps) {
</Button>
</div>
<form
/**
* Ignoring since ts doesn't recognize that tRPC
* parses FormData before reaching the route
* @ts-ignore */
/* @ts-expect-error Ignoring since ts doesn't recognize that tRPC parses FormData before reaching the route */
action={editProfile}
className={styles.form}
id={formId}

View File

@@ -204,6 +204,7 @@ export default function AddAncillaryFlowModal({
)
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function handleGuaranteePayment(data: AncillaryFormData, packages: any) {
const savedCreditCard = savedCreditCards?.find(
(card) => card.id === data.paymentMethod

View File

@@ -7,4 +7,4 @@ export const paymentSchema = z.object({
}),
})
export interface GuaranteeFormData extends z.output<typeof paymentSchema> {}
export type GuaranteeFormData = z.output<typeof paymentSchema>

View File

@@ -95,6 +95,7 @@ export default function TrackGuarantee({
break
case PaymentCallbackStatusEnum.Cancel:
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
isAncillaryFlow
? trackAncillaryPaymentEvent(
"GuaranteeCancelAncillary",
@@ -107,6 +108,7 @@ export default function TrackGuarantee({
break
case PaymentCallbackStatusEnum.Error:
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
isAncillaryFlow
? trackAncillaryPaymentEvent(
"GuaranteeFailAncillary",

View File

@@ -36,7 +36,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
) {
const intl = useIntl()
const { control } = useFormContext()
let numberAttributes: HTMLAttributes<HTMLInputElement> = {}
const numberAttributes: HTMLAttributes<HTMLInputElement> = {}
if (type === "number") {
numberAttributes.onWheel = function (evt: WheelEvent<HTMLInputElement>) {
evt.currentTarget.blur()

View File

@@ -15,6 +15,7 @@ interface ReactAriaSelectProps
showRadioButton?: boolean
discreet?: boolean
isNestedInModal?: boolean
// eslint-disable-next-line @typescript-eslint/no-explicit-any
optionsIcon?: ReactElement<any>
}

View File

@@ -13,7 +13,10 @@ const compat = new FlatCompat({
export default defineConfig([
{
extends: compat.extends("next/core-web-vitals", "plugin:import/typescript"),
extends: compat.extends(
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended"
),
plugins: {
"simple-import-sort": simpleImportSort,
"@typescript-eslint": typescriptEslint,
@@ -63,7 +66,6 @@ export default defineConfig([
],
},
],
"simple-import-sort/exports": "warn",
"import/first": "warn",
"import/newline-after-import": "warn",

View File

@@ -3,11 +3,11 @@ import type { PageContentTypeEnum } from "@scandic-hotels/trpc/enums/contentType
export type NextSearchParams = { [key: string]: string | string[] | undefined }
export type SearchParams<S = {}> = {
export type SearchParams<S = object> = {
searchParams: Promise<S & { [key: string]: string }>
}
export type Params<P = {}> = {
export type Params<P = object> = {
params: Promise<P>
}
@@ -50,7 +50,9 @@ export type PreviewParams = {
live_preview?: string
}
export type LayoutArgs<P = undefined> = P extends undefined ? {} : Params<P>
export type LayoutArgs<P = undefined> = P extends undefined
? unknown
: Params<P>
export type PageArgs<P = undefined, S = undefined> = LayoutArgs<P> &
(S extends undefined ? {} : SearchParams<S>)
(S extends undefined ? unknown : SearchParams<S>)

View File

@@ -18,7 +18,10 @@ const packageDir = path.dirname(fileURLToPath(import.meta.url))
export default defineConfig([
{
extends: compat.extends("next/core-web-vitals", "plugin:import/typescript"),
extends: compat.extends(
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended"
),
plugins: {
"simple-import-sort": simpleImportSort,
"@typescript-eslint": typescriptEslint,

View File

@@ -13,7 +13,7 @@ import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConf
import type { AdditionalInfoCookieValue } from "../../../../types/components/findMyBooking/additionalInfoCookieValue"
interface ManageBookingProps extends Pick<BookingConfirmation, "booking"> {}
type ManageBookingProps = Pick<BookingConfirmation, "booking">
export default function ManageBooking({ booking }: ManageBookingProps) {
const intl = useIntl()

View File

@@ -13,7 +13,7 @@ import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConf
import type { AdditionalInfoCookieValue } from "../../../types/components/findMyBooking/additionalInfoCookieValue"
export interface PromosProps extends Pick<BookingConfirmation, "booking"> {}
export type PromosProps = Pick<BookingConfirmation, "booking">
export function Promos({ booking }: PromosProps) {
const intl = useIntl()

View File

@@ -90,7 +90,7 @@ export default function BookingWidgetClient({
toDate = now.add(1, "day")
}
let selectedLocation =
const selectedLocation =
destinationsData?.currentSelection.hotel ??
destinationsData?.currentSelection.city
@@ -199,8 +199,9 @@ export default function BookingWidgetClient({
? JSON.parse(storedBookingCode)
: undefined
initialBookingCode?.remember &&
if (initialBookingCode?.remember) {
methods.setValue("bookingCode", initialBookingCode)
}
}
}, [methods, selectedBookingCode])

View File

@@ -84,7 +84,7 @@ export default function ChildInfoSelector({
]
function getAvailableBeds(age: number) {
let availableBedTypes: ChildBed[] = []
const availableBedTypes: ChildBed[] = []
if (age <= 5 && (adults > childrenInAdultsBed || child.bed === 0)) {
availableBedTypes.push(allBedTypes[0])
}

View File

@@ -63,7 +63,7 @@ export default function GuestsRoomsPickerForm({
const updateHeight = useCallback(() => {
// Get available space for picker to show without going beyond screen
const bookingWidget = document.getElementById("booking-widget")
let maxHeight =
const maxHeight =
window.innerHeight -
(bookingWidget?.getBoundingClientRect().bottom ?? 0) -
50

View File

@@ -13,4 +13,4 @@ export const paymentSchema = z.object({
guarantee: z.boolean(),
})
export interface PaymentFormData extends z.output<typeof paymentSchema> {}
export type PaymentFormData = z.output<typeof paymentSchema>

View File

@@ -17,10 +17,9 @@ import { formId } from "../../../Payment/PaymentClient"
import styles from "./bottomSheet.module.css"
interface SummaryBottomSheetProps
extends PropsWithChildren<{
isUserLoggedIn: boolean
}> {}
type SummaryBottomSheetProps = PropsWithChildren<{
isUserLoggedIn: boolean
}>
export default function SummaryBottomSheet({
children,

View File

@@ -46,6 +46,7 @@ export async function SelectHotel({
const isAllUnavailable = hotels.every(
(hotel) => hotel.availability.status !== "Available"
)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const isCityWithCountry = (city: any): city is { country: string } =>
"country" in city

View File

@@ -84,7 +84,7 @@ export function DesktopSummary({
isUserLoggedIn || selectedRates.rates.some(isBookingCodeRate)
const mainRoomRate = selectedRates.rates.at(0)
let mainRoomCurrency = getRoomCurrency(mainRoomRate)
const mainRoomCurrency = getRoomCurrency(mainRoomRate)
return (
<>

View File

@@ -159,6 +159,7 @@ function CorporateChequeCode({
handleSelectRate,
isSelected,
}: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
codeProduct: Extract<CodeProduct, { corporateCheque: any }>
roomIndex: number
roomTypeCode: string
@@ -329,6 +330,7 @@ function VoucherCode({
handleSelectRate,
isSelected,
}: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
codeProduct: Extract<CodeProduct, { voucher: any }>
roomIndex: number
roomTypeCode: string

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { describe, expect, it } from "vitest"
import { RateEnum } from "@scandic-hotels/common/constants/rate"

View File

@@ -345,11 +345,10 @@ function getRequestedAdditionalPrice(
}
}
interface TRoom
extends Pick<
RoomState["room"],
"adults" | "breakfast" | "guest" | "roomFeatures" | "roomRate"
> {}
type TRoom = Pick<
RoomState["room"],
"adults" | "breakfast" | "guest" | "roomFeatures" | "roomRate"
>
interface TRoomCorporateCheque extends TRoom {
roomRate: CorporateChequeProduct

View File

@@ -20,6 +20,7 @@ export type TrackingFunctions = {
includePathname?: boolean
roomTypeCode?: string | null
}) => void
// eslint-disable-next-line @typescript-eslint/no-explicit-any
trackGenericEvent(data: any): void
trackLoginClick(position: TrackingPosition & (string & {})): void
trackPaymentEvent(payment: PaymentEvent): void

View File

@@ -548,6 +548,7 @@ const getSearchParams = (input: string) => {
return searchParamsToObject(searchParams)
}
const searchParamsToObject = (searchParams: URLSearchParams) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const obj: Record<string, any> = {}
for (const [key, value] of searchParams.entries()) {
obj[key] = value

View File

@@ -20,6 +20,7 @@ export function parseSearchParams<T extends z.ZodRawShape>(
export function parseSearchParams<T extends z.ZodRawShape>(
searchParams: NextSearchParams,
options?: ParseOptions<T>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): Record<string, any>
/**
@@ -49,6 +50,7 @@ export function parseSearchParams<T extends z.ZodRawShape>(
const buildObject = getBuilder(options || {})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const resultObject: Record<string, any> = {}
for (const [key, value] of entries) {
const paths = key.split(".")
@@ -80,6 +82,7 @@ function getBuilder<T extends z.ZodRawShape>(options: ParseOptions<T>) {
const typeHints = options.typeHints || {}
return function buildNestedObject(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
obj: Record<string, any>,
paths: string[],
value: string
@@ -134,6 +137,7 @@ function getBuilder<T extends z.ZodRawShape>(options: ParseOptions<T>) {
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function isNotArray(value: any) {
return !value || typeof value !== "object" || !Array.isArray(value)
}
@@ -157,6 +161,7 @@ type SerializeOptions = {
* Arrays are not merged, they will always replace existing values.
*/
export function serializeSearchParams(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
obj: Record<string, any>,
options?: SerializeOptions
): URLSearchParams {