我现在有个接口如下:

interface GlobalSettings {
    navTheme: ThemeType
}

ThemeType 是上篇文章中定义的联合类型,类型为”dark“|”light“

现在有个defaultSettings默认值对象:

const defaultSettings: GlobalSetting = {
    navTheme: "light"
}

我将这个defaultSettings的值初始化到pina中做状态管理,使用了vueUse工具箱,代码如下:

export const useSettingsStore = defineStore('setting', () => {
    const navTheme = useStorage('navTheme', defaultSettings.navTheme)

    const themeConfig = reactive({
// themeAlgorithm[navTheme.value] 这句一直会报错
/** 
    元素隐式具有 "any" 类型,因为类型为 "string" 的表达式不能用于索引类型 "{ readonly light:         (token: SeedToken) => MapToken; readonly dark: DerivativeFunc<SeedToken, MapToken>; }"。
  在类型 "{ readonly light: (token: SeedToken) => MapToken; readonly dark: DerivativeFunc<SeedToken, MapToken>; }" 上找不到具有类型为 "string" 的参数的索引签名。ts(7053)
*/
      algorithm: themeAlgorithm[navTheme.value] || antdTheme.defaultAlgorithm
    })
})

 

 上面报错的意思是useStorage返回的类型是RemovableRef<string>。 那我就纳闷了,defaultSettings.navTheme 明明定义的时候是ThemeType类型,为什么useStoreage返回的是string呢?

然后去查看useStroage文档,如下是它的类型声明:

export interface Serializer<T> {
  read: (raw: string) => T
  write: (value: T) => string
}
export interface SerializerAsync<T> {
  read: (raw: string) => Awaitable<T>
  write: (value: T) => Awaitable<string>
}
export declare const StorageSerializers: Record<
  "boolean" | "object" | "number" | "any" | "string" | "map" | "set" | "date",
  Serializer<any>
>
export declare const customStorageEventName = "vueuse-storage"
export interface StorageEventLike {
  storageArea: StorageLike | null
  key: StorageEvent["key"]
  oldValue: StorageEvent["oldValue"]
  newValue: StorageEvent["newValue"]
}
export interface UseStorageOptions<T>
  extends ConfigurableEventFilter,
    ConfigurableWindow,
    ConfigurableFlush {
  /**
   * Watch for deep changes
   *
   * @default true
   */
  deep?: boolean
  /**
   * Listen to storage changes, useful for multiple tabs application
   *
   * @default true
   */
  listenToStorageChanges?: boolean
  /**
   * Write the default value to the storage when it does not exist
   *
   * @default true
   */
  writeDefaults?: boolean
  /**
   * Merge the default value with the value read from the storage.
   *
   * When setting it to true, it will perform a **shallow merge** for objects.
   * You can pass a function to perform custom merge (e.g. deep merge), for example:
   *
   * @default false
   */
  mergeDefaults?: boolean | ((storageValue: T, defaults: T) => T)
  /**
   * Custom data serialization
   */
  serializer?: Serializer<T>
  /**
   * On error callback
   *
   * Default log error to `console.error`
   */
  onError?: (error: unknown) => void
  /**
   * Use shallow ref as reference
   *
   * @default false
   */
  shallow?: boolean
  /**
   * Wait for the component to be mounted before reading the storage.
   *
   * @default false
   */
  initOnMounted?: boolean
}
export declare function useStorage(
  key: MaybeRefOrGetter<string>,
  defaults: MaybeRefOrGetter<string>,
  storage?: StorageLike,
  options?: UseStorageOptions<string>,
): RemovableRef<string>
export declare function useStorage(
  key: MaybeRefOrGetter<string>,
  defaults: MaybeRefOrGetter<boolean>,
  storage?: StorageLike,
  options?: UseStorageOptions<boolean>,
): RemovableRef<boolean>
export declare function useStorage(
  key: MaybeRefOrGetter<string>,
  defaults: MaybeRefOrGetter<number>,
  storage?: StorageLike,
  options?: UseStorageOptions<number>,
): RemovableRef<number>
export declare function useStorage<T>(
  key: MaybeRefOrGetter<string>,
  defaults: MaybeRefOrGetter<T>,
  storage?: StorageLike,
  options?: UseStorageOptions<T>,
): RemovableRef<T>
export declare function useStorage<T = unknown>(
  key: MaybeRefOrGetter<string>,
  defaults: MaybeRefOrGetter<null>,
  storage?: StorageLike,
  options?: UseStorageOptions<T>,
): RemovableRef<T>

正常来说useStorage应该能够根据默认值的类型,返回跟默认值类型一样的类型的,但是现实是没有,后来我给useStorage加了个范型才得到解决,代码如下:

看官方文档,我的理解是对原始类型,useStorage能够自动拆箱成正确的类型,对于其他对象类型或自定义类型,则需要显式的给到useStorage范型类型。 

更多推荐