Skip to content

Commit

Permalink
enable typescript strict mode (#741)
Browse files Browse the repository at this point in the history
* use tuple to replace overload

* use es6 default value to replace object.assign

* improve onErrorRetry types

* enable strict mode and fix use-swr-infinite

* type global state manager

* safely fix ts error using @ts-ignore and any

* fix test

* fix eslint and window.requestIdleCallback type

* keep same order

* more strict config callback fn type

* fix fetcherFn type

* keep the exact same behavior

Co-authored-by: Shu Ding <[email protected]>
  • Loading branch information
promer94 and shuding authored Oct 31, 2020
1 parent e476ed5 commit df5f623
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 138 deletions.
9 changes: 8 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
module.exports = {
preset: 'ts-jest',
testRegex: '/test/.*\\.test\\.tsx$',
};
globals: {
'ts-jest': {
diagnostics: {
warnOnly: true
}
}
}
}
19 changes: 11 additions & 8 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/ban-ts-ignore */
/* TODO: use @ts-expect-error after upgrading typescript verison */
import { dequal } from 'dequal/lite'
import {
ConfigInterface,
Expand All @@ -12,11 +14,11 @@ const cache = new Cache()

// error retry
function onErrorRetry(
_,
__,
config: ConfigInterface,
_: unknown,
__: string,
config: Readonly<Required<ConfigInterface>>,
revalidate: revalidateType,
opts: RevalidateOptionInterface
opts: Required<RevalidateOptionInterface>
): void {
if (!config.isDocumentVisible()) {
// if it's hidden, stop
Expand All @@ -32,7 +34,7 @@ function onErrorRetry(
}

// exponential backoff
const count = Math.min(opts.retryCount || 0, 8)
const count = Math.min(opts.retryCount, 8)
const timeout =
~~((Math.random() + 0.5) * (1 << count)) * config.errorRetryInterval
setTimeout(revalidate, timeout, opts)
Expand All @@ -43,11 +45,13 @@ function onErrorRetry(
// slow connection (<= 70Kbps)
const slowConnection =
typeof window !== 'undefined' &&
// @ts-ignore
navigator['connection'] &&
// @ts-ignore
['slow-2g', '2g'].indexOf(navigator['connection'].effectiveType) !== -1

// config
const defaultConfig: ConfigInterface = {
const defaultConfig = {
// events
onLoadingSlow: () => {},
onSuccess: () => {},
Expand All @@ -67,13 +71,12 @@ const defaultConfig: ConfigInterface = {
shouldRetryOnError: true,
suspense: false,
compare: dequal,

fetcher: webPreset.fetcher,
isOnline: webPreset.isOnline,
isDocumentVisible: webPreset.isDocumentVisible,
setOnFocus: webPreset.setOnFocus,
setOnConnect: webPreset.setOnConnect
}
} as const

export { cache }
export default defaultConfig
8 changes: 4 additions & 4 deletions src/libs/web-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ function isDocumentVisible(): boolean {
return true
}

function setOnFocus(callback) {
const fetcher = (url: any) => fetch(url).then(res => res.json())

function setOnFocus(callback: (...args: unknown[]) => void) {
if (!isWindowEventTarget) return
window.addEventListener('focus', callback, false)
window.addEventListener('visibilitychange', callback, false)
}

function setOnConnect(callback) {
function setOnConnect(callback: (...args: unknown[]) => void) {
if (!isWindowEventTarget) return
window.addEventListener('online', callback, false)
}

const fetcher = url => fetch(url).then(res => res.json())

export default {
isOnline,
isDocumentVisible,
Expand Down
25 changes: 16 additions & 9 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type fetcherFn<Data> = ((...args: any) => Data | Promise<Data>) | null
export type fetcherFn<Data> = (...args: any) => Data | Promise<Data>
export interface ConfigInterface<
Data = any,
Error = any,
Expand All @@ -19,33 +19,40 @@ export interface ConfigInterface<
fetcher?: Fn
suspense?: boolean
initialData?: Data

onLoadingSlow?: (
key: string,
config: Readonly<Required<ConfigInterface<Data, Error>>>
) => void
isOnline?: () => boolean
isDocumentVisible?: () => boolean
onLoadingSlow?: (key: string, config: ConfigInterface<Data, Error>) => void
onSuccess?: (
data: Data,
key: string,
config: ConfigInterface<Data, Error>
config: Readonly<Required<ConfigInterface<Data, Error>>>
) => void
onError?: (
err: Error,
key: string,
config: ConfigInterface<Data, Error>
config: Readonly<Required<ConfigInterface<Data, Error>>>
) => void
onErrorRetry?: (
err: Error,
key: string,
config: ConfigInterface<Data, Error>,
config: Readonly<Required<ConfigInterface<Data, Error>>>,
revalidate: revalidateType,
revalidateOpts: RevalidateOptionInterface
opts: Required<RevalidateOptionInterface>
) => void
setOnFocus?(callback?): void
setOnConnect?(callback?): void
setOnFocus?: ListenerInterface['setOnConnect']
setOnConnect?: ListenerInterface['setOnFocus']

compare?: (a: Data | undefined, b: Data | undefined) => boolean
}

export interface ListenerInterface {
setOnFocus: (callback: (...args: any[]) => void) => void
setOnConnect: (callback: (...args: any[]) => void) => void
}

export interface RevalidateOptionInterface {
retryCount?: number
dedupe?: boolean
Expand Down
70 changes: 28 additions & 42 deletions src/use-swr-infinite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,58 +29,44 @@ type SWRInfiniteResponseInterface<Data = any, Error = any> = responseInterface<
}

function useSWRInfinite<Data = any, Error = any>(
getKey: KeyLoader<Data>
): SWRInfiniteResponseInterface<Data, Error>
function useSWRInfinite<Data = any, Error = any>(
getKey: KeyLoader<Data>,
config?: SWRInfiniteConfigInterface<Data, Error>
): SWRInfiniteResponseInterface<Data, Error>
function useSWRInfinite<Data = any, Error = any>(
getKey: KeyLoader<Data>,
fn?: fetcherFn<Data>,
config?: SWRInfiniteConfigInterface<Data, Error>
): SWRInfiniteResponseInterface<Data, Error>
function useSWRInfinite<Data = any, Error = any>(
...args
...args:
| readonly [KeyLoader<Data>]
| readonly [KeyLoader<Data>, fetcherFn<Data>]
| readonly [KeyLoader<Data>, SWRInfiniteConfigInterface<Data, Error>]
| readonly [
KeyLoader<Data>,
fetcherFn<Data>,
SWRInfiniteConfigInterface<Data, Error>
]
): SWRInfiniteResponseInterface<Data, Error> {
let getKey: KeyLoader<Data>,
fn: fetcherFn<Data> | undefined,
config: SWRInfiniteConfigInterface<Data, Error> = {}
const getKey = args[0]

if (args.length >= 1) {
getKey = args[0]
}
if (args.length > 2) {
fn = args[1]
config = args[2]
} else {
if (typeof args[1] === 'function') {
fn = args[1]
} else if (typeof args[1] === 'object') {
config = args[1]
}
}

config = Object.assign(
const config = Object.assign(
{},
defaultConfig,
useContext(SWRConfigContext),
config
args.length > 2
? args[2]
: args.length === 2 && typeof args[1] === 'object'
? args[1]
: {}
)
let {
// in typescript args.length > 2 is not same as args.lenth === 3
// we do a safe type assertion by ourself here
// args.length === 3
const fn = (args.length > 2
? args[1]
: args.length === 2 && typeof args[1] === 'function'
? args[1]
: config.fetcher) as fetcherFn<Data>

const {
initialSize = 1,
revalidateAll = false,
persistSize = false,
fetcher: defaultFetcher,
...extraConfig
} = config

if (typeof fn === 'undefined') {
// use the global fetcher
// we have to convert the type here
fn = (defaultFetcher as unknown) as fetcherFn<Data>
}

// get the serialized key of the first page
let firstPageKey: string | null = null
try {
Expand Down Expand Up @@ -178,7 +164,7 @@ function useSWRInfinite<Data = any, Error = any>(
)

// keep the data inside a ref
const dataRef = useRef<Data[]>(swr.data)
const dataRef = useRef(swr.data)
useEffect(() => {
dataRef.current = swr.data
}, [swr.data])
Expand Down Expand Up @@ -210,7 +196,7 @@ function useSWRInfinite<Data = any, Error = any>(
}
cache.set(pageCountCacheKey, pageCountRef.current)
rerender(v => !v)
return mutate(v => v)
return mutate((v: any) => v)
},
[mutate, pageCountCacheKey]
)
Expand Down
Loading

0 comments on commit df5f623

Please sign in to comment.