config.tsx


Overview

The config.tsx file serves as a comprehensive test and demonstration suite for the type safety, configuration, and usage patterns of the SWR React Hooks library, specifically focusing on its configuration system (SWRConfig), caching, fallback data, suspense mode, and type inference behaviors.

Rather than providing runtime features directly, this file primarily contains TypeScript type tests and React component snippets that verify the correct typing of SWR hooks and configurations across various use cases. The tests use expectType assertions to ensure type correctness and demonstrate best practices or limitations of SWR's API with TypeScript.

The file is especially useful for library authors, maintainers, or advanced users who want to understand or verify how SWR’s generic types, configuration options, and data fetching hooks interact in complex scenarios.


Detailed Explanations

Imported Modules and Types


Functions

Each exported function tests or demonstrates a specific aspect of SWR configuration or usage.


testCache()

export function testCache() {
  expectType<Cache<any>>(useSWRConfig().cache)
}

Usage: Ensures the global cache object from configuration has the correct type.


testCustomSWRConfig()

export function testCustomSWRConfig() {
  const noNull = [
    // @ts-expect-error
    <SWRConfig key={'null'} value={null} />,
    // @ts-expect-error
    <SWRConfig key={'callback-return-null'} value={() => null} />
  ]

  return (
    <>
      {noNull}
      <SWRConfig value={undefined} />
      <SWRConfig value={() => ({})} />
      <SWRConfig
        value={{
          fallback: {
            '/api': 'fallback',
            '/api2': Promise.resolve('fallback2')
          }
        }}
      />

      <SWRConfig
        // @ts-expect-error
        value={() => 0}
      />
    </>
  )
}

Usage: Useful for validating configuration values in SWR context provider.


testFullConfiguration()

export function testFullConfiguration() {
  type IData = { value: string }
  type IError = { error: any }
  type IConfig = FullConfiguration<IData, IError>

  const config: IConfig = SWRConfig.defaultValue
  expectType<IData | Promise<IData> | undefined>(config.fallbackData)
}

Usage: Ensures correct typing of full SWR configuration objects.


testSWRResponseCachedDataTypes()

export function testSWRResponseCachedDataTypes() {
  type FilledData = SWRResponse<string, any, { suspense: true }>['data']
  expectType<Equal<FilledData, string>>(true)

  type FilledConditionalData = SWRResponse<
    string | number,
    any,
    { suspense: true }
  >['data']
  expectType<Equal<FilledConditionalData, string | number>>(true)
}

Usage: Ensures that suspense mode correctly infers data types from SWR responses.


testSuspense()

export function testSuspense() {
  // Basic
  const { data: data1 } = useSWR('/api', (k: string) => Promise.resolve(k), {
    suspense: true
  })
  expectType<string>(data1)

  // Basic(default fetcher)
  const { data: data2 } = useSWR('/api', {
    suspense: true
  })
  expectType<any>(data2)

  // Explicit generics lose partial inference
  const { data: data3 } = useSWR<string>(
    '/api',
    (k: string) => Promise.resolve(k),
    { suspense: true }
  )
  expectType<string | undefined>(data3)

  const { data: data4 } = useSWR<string, any, { suspense: true }>(
    '/api',
    (k: string) => Promise.resolve(k),
    { suspense: true }
  )
  expectType<string>(data4)
}

Usage: Guides developers on how to correctly type suspense-enabled SWR hooks.


testFallbackData()

export function testFallbackData() {
  // Basic
  const fetcher1 = (k: string) => Promise.resolve(k)
  const { data: data1 } = useSWR('/api', fetcher1, {
    fallbackData: 'fallback'
  })
  expectType<string>(data1)

  // Conditional
  const fetcher2 = (k: string) =>
    Promise.resolve(Math.random() > 0.5 ? k : Math.random() * 100)
  const { data: data2 } = useSWR('/api', fetcher2, {
    fallbackData: 'fallback'
  })
  expectType<string | number>(data2)

  // Complex
  const fetcher3 = (k: string) => Promise.resolve({ value: k })
  const { data: data3 } = useSWR('/api', fetcher3, {
    fallbackData: { value: 'fallback' }
  })
  expectType<{ value: string }>(data3)

  // Without specific fetcher
  const { data: data4 } = useSWR('/api', { fallbackData: 'fallback' })
  expectType<any>(data4)

  // Explicit generics and fallbackData combinations
  const { data: data5 } = useSWR<string>(
    '/api',
    (k: string) => Promise.resolve(k),
    { fallbackData: 'fallback' }
  )
  expectType<string | undefined>(data5)

  const { data: data6 } = useSWR<string, any, { fallbackData: 'fallback' }>(
    '/api',
    (k: string) => Promise.resolve(k),
    { fallbackData: 'fallback' }
  )
  expectType<string>(data6)

  // Promise fallbackData
  const { data: data7 } = useSWR<
    string,
    any,
    { fallbackData: Promise<'fallback'> }
  >('/api', (k: string) => Promise.resolve(k), {
    fallbackData: Promise.resolve('fallback')
  })
  expectType<string>(data7)

  // Declaring fallbackData exists in config
  const { data: data8 } = useSWR<string, any, { fallbackData: string }>('/api')
  const { data: data9 } = useSWR<string, any, { fallbackData: string }>(
    '/api',
    {}
  )
  expectType<string>(data8)
  expectType<string>(data9)
}

Usage: Provides a thorough reference on how fallbackData affects SWR's data type inference.


testConfigAsSWRConfiguration()

export function testConfigAsSWRConfiguration() {
  const fetcher = (k: string) => Promise.resolve({ value: k })
  const { data } = useSWR('/api', fetcher, {} as SWRConfiguration)
  expectType<Equal<typeof data, { value: string } | undefined>>(true)
}

Usage: Useful for ensuring type compatibility when explicitly casting config.


testEmptyConfig()

export function testEmptyConfig() {
  const fetcher = (k: string) => Promise.resolve({ value: k })
  const { data, error, isLoading } = useSWR<{ value: string }, Error>(
    '/api',
    fetcher,
    {}
  )
  expectType<Equal<typeof data, { value: string } | undefined>>(true)
  expectType<Equal<typeof error, Error | undefined>>(true)
  expectType<Equal<typeof isLoading, boolean>>(true)
}

Usage: Shows default SWR states and typings.


testFallbackDataConfig()

export function testFallbackDataConfig() {
  const fetcher = (k: string) => Promise.resolve({ value: k })
  const { data, isLoading } = useSWR('/api', fetcher, {
    fallbackData: { value: 'fallback' }
  })
  expectType<Equal<typeof data, { value: string }>>(true)
  expectType<Equal<typeof isLoading, boolean>>(true)
}

Usage: Demonstrates that fallbackData removes undefined from data type.


testProviderConfig()

export function testProviderConfig() {
  const GlobalSetting = ({ children }: { children: React.ReactNode }) => {
    return (
      <SWRConfig
        value={{
          provider: () => new Map(),
          isOnline() {
            /* Customize the network state detector */
            return true
          },
          isVisible() {
            /* Customize the visibility state detector */
            return true
          },
          initFocus(_callback) {
            /* Register the listener with your state provider */
          },
          initReconnect(_callback) {
            /* Register the listener with your state provider */
          }
        }}
      >
        {children}
      </SWRConfig>
    )
  }
  return (
    <GlobalSetting>
      <div />
    </GlobalSetting>
  )
}

Usage: Shows how to globally customize SWR's behavior in a React app.


Important Implementation Details


Interaction with Other Parts of the System


Visual Diagram: Component and Function Relationships

flowchart TD
  subgraph SWRConfig Provider Tests
    A[testCustomSWRConfig()]
    B[testProviderConfig()]
  end

  subgraph SWR Hook Usage Tests
    C[testSuspense()]
    D[testFallbackData()]
    E[testConfigAsSWRConfiguration()]
    F[testEmptyConfig()]
    G[testFallbackDataConfig()]
    H[testSWRResponseCachedDataTypes()]
  end

  subgraph Type Utilities
    I[testCache()]
    J[testFullConfiguration()]
  end

  A --> B
  C --> H
  D --> H
  E --> F
  F --> G
  I --> J

Usage Summary

This file is primarily intended to:


End of config.tsx Documentation