Skip to content

Commit

Permalink
♻️ Prefer type over interface (#515)
Browse files Browse the repository at this point in the history
  • Loading branch information
juliencrn committed Feb 27, 2024
1 parent b3d4058 commit 072b7e6
Show file tree
Hide file tree
Showing 31 changed files with 72 additions and 51 deletions.
7 changes: 7 additions & 0 deletions .changeset/giant-moles-double.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"www": minor
"eslint-config-custom": minor
"usehooks-ts": major
---

Prefer type over interface (#515)
2 changes: 1 addition & 1 deletion apps/www/src/app/(docs)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { DocsSidebarNav } from '@/components/sidebar-nav'
import { docsConfig } from '@/config/docs'
import { siteConfig } from '@/config/site'

interface DocsLayoutProps {
type DocsLayoutProps = {
children: React.ReactNode
}

Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/app/(marketing)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { MainNav } from '@/components/main-nav'
import { marketingConfig } from '@/config/marketing'
import { siteConfig } from '@/config/site'

interface MarketingLayoutProps {
type MarketingLayoutProps = {
children: React.ReactNode
}

Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const fontHeading = localFont({
variable: '--font-heading',
})

interface RootLayoutProps {
type RootLayoutProps = {
children: React.ReactNode
}

Expand Down
4 changes: 2 additions & 2 deletions apps/www/src/components/command-copy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import {
} from './ui/dropdown-menu'
import { cn } from '@/lib/utils'

interface CommandCopyProps extends ComponentProps<'code'> {
type CommandCopyProps = {
command: Record<string, string> | string
defaultCommand?: string
}
} & ComponentProps<'code'>

export function CommandCopy({
className,
Expand Down
4 changes: 2 additions & 2 deletions apps/www/src/components/docs-page-header.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { cn } from '@/lib/utils'

interface DocsPageHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
type DocsPageHeaderProps = {
heading: string
text?: string
}
} & React.HTMLAttributes<HTMLDivElement>

export function DocsPageHeader({
heading,
Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/components/main-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { siteConfig } from '@/config/site'
import { cn } from '@/lib/utils'
import type { MainNavItem } from '@/types'

interface MainNavProps {
type MainNavProps = {
items?: MainNavItem[]
children?: React.ReactNode
}
Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/components/mobile-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { siteConfig } from '@/config/site'
import { cn } from '@/lib/utils'
import type { MainNavItem } from '@/types'

interface MobileNavProps {
type MobileNavProps = {
items: MainNavItem[]
children?: React.ReactNode
}
Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/components/paper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { buttonVariants } from '@/components/ui/button'
import { getPosts } from '@/lib/mdx'
import { cn } from '@/lib/utils'

interface DocsPagerProps {
type DocsPagerProps = {
slug: string
}

Expand Down
4 changes: 2 additions & 2 deletions apps/www/src/components/sidebar-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { usePathname } from 'next/navigation'
import { cn } from '@/lib/utils'
import type { SidebarNavItem } from '@/types'

export interface DocsSidebarNavProps {
type DocsSidebarNavProps = {
items: SidebarNavItem[]
}

Expand All @@ -29,7 +29,7 @@ export function DocsSidebarNav({ items }: DocsSidebarNavProps) {
) : null
}

interface DocsSidebarNavItemsProps {
type DocsSidebarNavItemsProps = {
items: SidebarNavItem[]
pathname: string | null
}
Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/components/table-of-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ function useActiveItem(itemIds: (string | undefined)[]) {
return activeId
}

interface TreeProps {
type TreeProps = {
tree: TableOfContents
level?: number
activeItem?: string | null
Expand Down
7 changes: 3 additions & 4 deletions apps/www/src/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,10 @@ const buttonVariants = cva(
},
)

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
export type ButtonProps = {
asChild?: boolean
}
} & React.ButtonHTMLAttributes<HTMLButtonElement> &
VariantProps<typeof buttonVariants>

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export type MarketingConfig = {
mainNav: MainNavItem[]
}

export interface Post {
export type Post = {
name: string // useHook
slug: string // use-hook
href: string // /react-hook/use-hook
Expand Down
14 changes: 13 additions & 1 deletion packages/eslint-config-custom/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,21 @@ module.exports = {
},
],

// Opinionated: no enums
'no-restricted-syntax': [
'warn',
{
selector: 'TSEnumDeclaration',
message: 'Prefer union type',
},
],

// Opinionated: prefer "type" over "interface"
'@typescript-eslint/consistent-type-definitions': ['warn', 'type'],

// Disable some TypeScript rules
'@typescript-eslint/explicit-module-boundary-types': 'off', // Too noisy
'@typescript-eslint/consistent-type-definitions': 'off', // Will come in v3
// '@typescript-eslint/consistent-type-definitions': 'off', // Will come in v3
'@typescript-eslint/no-unnecessary-condition': 'off', // TODO: Enable it
'@typescript-eslint/prefer-ts-expect-error': 'off',
},
Expand Down
2 changes: 1 addition & 1 deletion packages/usehooks-ts/src/useBoolean/useBoolean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useCallback, useState } from 'react'

import type { Dispatch, SetStateAction } from 'react'

interface UseBooleanOutput {
type UseBooleanOutput = {
value: boolean
setValue: Dispatch<SetStateAction<boolean>>
setTrue: () => void
Expand Down
4 changes: 2 additions & 2 deletions packages/usehooks-ts/src/useCountdown/useCountdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { useBoolean } from '../useBoolean'
import { useCounter } from '../useCounter'
import { useInterval } from '../useInterval'

interface CountdownOptions {
type CountdownOptions = {
countStart: number
intervalMs?: number
isIncrement?: boolean
countStop?: number
}

interface CountdownControllers {
type CountdownControllers = {
startCountdown: () => void
stopCountdown: () => void
resetCountdown: () => void
Expand Down
2 changes: 1 addition & 1 deletion packages/usehooks-ts/src/useCounter/useCounter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState } from 'react'

import type { Dispatch, SetStateAction } from 'react'

interface UseCounterOutput {
type UseCounterOutput = {
count: number
increment: () => void
decrement: () => void
Expand Down
2 changes: 1 addition & 1 deletion packages/usehooks-ts/src/useDarkMode/useDarkMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type DarkModeOptions = {
initializeWithValue?: boolean
}

interface DarkModeOutput {
type DarkModeOutput = {
isDarkMode: boolean
toggle: () => void
enable: () => void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useUnmount } from '../useUnmount'
/**
* Configuration options for controlling the behavior of the debounced function.
*/
export interface DebounceOptions {
export type DebounceOptions = {
/**
* Determines whether the function should be invoked on the leading edge of the timeout.
*/
Expand All @@ -25,7 +25,7 @@ export interface DebounceOptions {
/**
* Functions to manage a debounced callback.
*/
interface ControlFunctions {
type ControlFunctions = {
/**
* Cancels pending function invocations.
*/
Expand All @@ -48,10 +48,10 @@ interface ControlFunctions {
* Ensure proper handling in your code.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export interface DebouncedState<T extends (...args: any) => ReturnType<T>>
extends ControlFunctions {
(...args: Parameters<T>): ReturnType<T> | undefined
}
export type DebouncedState<T extends (...args: any) => ReturnType<T>> = ((
...args: Parameters<T>
) => ReturnType<T> | undefined) &
ControlFunctions

/**
* Hook to create a debounced version of a callback function.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/consistent-type-definitions */
import { fireEvent, renderHook } from '@testing-library/react'

import { useEventListener } from './useEventListener'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ type ObserverCallback = (
* @property {ObserverCallback} [onChange] - A callback function to be invoked when the intersection state changes.
* @property {boolean} [initialIsIntersecting=false] - The initial state of the intersection.
*/
interface IntersectionObserverOptions extends IntersectionObserverInit {
type IntersectionObserverOptions = {
freezeOnceVisible?: boolean
onChange?: ObserverCallback
initialIsIntersecting?: boolean
}
} & IntersectionObserverInit

/** Supports both array and object destructing */
type IntersectionResult = [
Expand Down
5 changes: 3 additions & 2 deletions packages/usehooks-ts/src/useLocalStorage/useLocalStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import { useEventCallback } from '../useEventCallback'
import { useEventListener } from '../useEventListener'

declare global {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface WindowEventMap {
'local-storage': CustomEvent
}
}

interface UseLocalStorageOptions<T> {
type UseLocalStorageOptions<T> = {
serializer?: (value: T) => string
deserializer?: (value: string) => T
initializeWithValue?: boolean
Expand Down Expand Up @@ -140,7 +141,7 @@ export function useLocalStorage<T>(

const handleStorageChange = useCallback(
(event: StorageEvent | CustomEvent) => {
if ((event as StorageEvent)?.key && (event as StorageEvent).key !== key) {
if ((event as StorageEvent).key && (event as StorageEvent).key !== key) {
return
}
setStoredValue(readValue())
Expand Down
2 changes: 1 addition & 1 deletion packages/usehooks-ts/src/useMap/useMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type MapOrEntries<K, V> = Map<K, V> | [K, V][]
* @template K - The type of keys in the map.
* @template V - The type of values in the map.
*/
export interface Actions<K, V> {
export type Actions<K, V> = {
set: (key: K, value: V) => void
setAll: (entries: MapOrEntries<K, V>) => void
remove: (key: K) => void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const IS_SERVER = typeof window === 'undefined'
* Represents the type for the options available when reading from local storage.
* @template T - The type of the stored value.
*/
interface Options<T, InitializeWithValue extends boolean | undefined> {
type Options<T, InitializeWithValue extends boolean | undefined> = {
deserializer?: (value: string) => T
initializeWithValue: InitializeWithValue
}
Expand Down Expand Up @@ -103,7 +103,7 @@ export function useReadLocalStorage<T>(

const handleStorageChange = useCallback(
(event: StorageEvent | CustomEvent) => {
if ((event as StorageEvent)?.key && (event as StorageEvent).key !== key) {
if ((event as StorageEvent).key && (event as StorageEvent).key !== key) {
return
}
setStoredValue(readValue())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ export function useResizeObserver<T extends HTMLElement = HTMLElement>(
const isMounted = useIsMounted()
const previousSize = useRef<Size>({ ...initialSize })
const onResize = useRef<ResizeHandler | undefined>(undefined)
onResize.current = options?.onResize
onResize.current = options.onResize

useEffect(() => {
if (!ref?.current) return
if (!ref.current) return

if (typeof window === 'undefined' || !('ResizeObserver' in window)) return

Expand All @@ -86,7 +86,7 @@ export function useResizeObserver<T extends HTMLElement = HTMLElement>(
previousSize.current.width = newWidth
previousSize.current.height = newHeight

if (onResize?.current) {
if (onResize.current) {
onResize.current(newSize)
} else {
if (isMounted()) {
Expand Down
4 changes: 2 additions & 2 deletions packages/usehooks-ts/src/useScreen/useScreen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ export function useScreen(

const debouncedSetScreen = useDebounceCallback(
setScreen,
options?.debounceDelay,
options.debounceDelay,
)

/** Handles the resize event of the window. */
function handleSize() {
const newScreen = readScreen()
const setSize = options?.debounceDelay ? debouncedSetScreen : setScreen
const setSize = options.debounceDelay ? debouncedSetScreen : setScreen

if (newScreen) {
// Create a shallow clone to trigger a re-render (#280).
Expand Down
2 changes: 1 addition & 1 deletion packages/usehooks-ts/src/useScript/useScript.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react'

export type UseScriptStatus = 'idle' | 'loading' | 'ready' | 'error'
export interface UseScriptOptions {
export type UseScriptOptions = {
shouldPreventLoad?: boolean
removeOnUnmount?: boolean
}
Expand Down
4 changes: 2 additions & 2 deletions packages/usehooks-ts/src/useScrollLock/useScrollLock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { useRef } from 'react'

import { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect'

interface UseScrollLockOptions {
type UseScrollLockOptions = {
autoLock: boolean
lockTarget: HTMLElement | string
widthReflow: boolean
}

interface UseScrollLockResult {
type UseScrollLockResult = {
lock: () => void
unlock: () => void
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useEventCallback } from '../useEventCallback'
import { useEventListener } from '../useEventListener'

declare global {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface WindowEventMap {
'session-storage': CustomEvent
}
Expand All @@ -18,7 +19,7 @@ declare global {
* @property {(value: T) => string} [serializer] - A function to serialize the value before storing it.
* @property {(value: string) => T} [deserializer] - A function to deserialize the stored value.
*/
interface UseSessionStorageOptions<T> {
type UseSessionStorageOptions<T> = {
serializer?: (value: T) => string
deserializer?: (value: string) => T
initializeWithValue?: boolean
Expand Down Expand Up @@ -149,7 +150,7 @@ export function useSessionStorage<T>(

const handleStorageChange = useCallback(
(event: StorageEvent | CustomEvent) => {
if ((event as StorageEvent)?.key && (event as StorageEvent).key !== key) {
if ((event as StorageEvent).key && (event as StorageEvent).key !== key) {
return
}
setStoredValue(readValue())
Expand Down
Loading

0 comments on commit 072b7e6

Please sign in to comment.