typescript如何正确判断useTitle的option类型?

最近在学习typescript的使用, 因此在学习vueuse中ts的使用,其中有个问题疑惑的问题
useTitle源码

export function useTitle(
  newTitle: MaybeComputedRef<string | null | undefined> = null,
  options: UseTitleOptions = {},
) {
  /*
    `titleTemplate` that returns the modified input string will make
    the `document.title` to be different from the `title.value`,
    causing the title to update infinitely if `observe` is set to `true`.
  */
  const {
    document = defaultDocument,
  } = options

  const title: WritableComputedRef<string | null | undefined> = resolveRef(newTitle ?? document?.title ?? null)
  const isReadonly = newTitle && isFunction(newTitle)

  function format(t: string) {
    if (!('titleTemplate' in options))
      return t
    const template = options.titleTemplate || '%s'
    return isFunction(template)
      ? template(t)
      : unref(template).replace(/%s/g, t)
  }

  watch(
    title,
    (t, o) => {
      if (t !== o && document)
        document.title = format(isString(t) ? t : '')
    },
    { immediate: true },
  )

  if ((options as any).observe && !(options as any).titleTemplate && document && !isReadonly) {
    useMutationObserver(
      document.head?.querySelector('title'),
      () => {
        if (document && document.title !== title.value)
          title.value = format(document.title)
      },
      { childList: true },
    )
  }

  return title
}

其中的options要先断言为any才能引用属性, 是否有其他办法使其更好的用到类型定义呢?

入参定义

export type UseTitleOptionsBase =
{
  /**
   * Observe `document.title` changes using MutationObserve
   * Cannot be used together with `titleTemplate` option.
   *
   * @default false
   */
  observe?: boolean
}
| {
  /**
   * The template string to parse the title (e.g., '%s | My Website')
   * Cannot be used together with `observe` option.
   *
   * @default '%s'
   */
  titleTemplate?: MaybeRef<string> | ((title: string) => string)
}

export type UseTitleOptions = ConfigurableDocument & UseTitleOptionsBase

是不是因为这里UseTitleOptionsBase是个联合类型, 来实现observetitleTemplate的互斥需求导致的?

阅读 2.2k
2 个回答
if ((options as any).observe && !(options as any).titleTemplate && document && !isReadonly)

如果不把options断言成anyoptions.observeoptions.titleTemplate会报错,
你也可以断言成符合你要求的类型

(options as { observe?: boolean }).observe
(options as { titleTemplate?: MaybeRef<string> | ((title: string) => string) }).titleTemplate

不过这么写代码有点过于冗余了
还有一种方法是让ts自动推导,改成

if (('observe' in options && options.observe) && !('titleTemplate' in options) && document && !isReadonly) 

这里因为他在判断之后没有取用options.observe的值,所以用any最方便,虽然一般来说不太推荐断言成any

可以参考这个demo

as any 可以用 in,typescript 会自动推导,但是要额外判断下 options.observe 是否为 ture.

CleanShot 2023-02-07 at 17.14.14@2x.png

推荐问题
logo
Microsoft
子站问答
访问
宣传栏