SPAでのメタタグ変更

## setHeadTag
```typescript
const baseMetas: Meta[] = [
  { name: 'keyword', content: null },
  { name: 'description', content: null },
  { property: 'og:url', content: null },
  { property: 'og:type', content: null },
  { property: 'og:description', content: null },
  { property: 'og:title', content: null },
  { property: 'og:site_name', content: null },
  { property: 'og:image', content: null }
]

const mergeMetas = (metas: Meta[]) =>
  metas.reduce((memo, meta) => {
    let overrided = false
    const metas = memo.map(base => {
      if (
        (base.name && base.name === meta.name) ||
        (base.property && base.property === meta.property)
      ) {
        overrided = true
        return meta
      }
      return base
    })
    if (overrided) return metas
    return [...memo, meta]
  }, baseMetas)

export const setHeadTags = (headTags: HeadTags) => {
  if (!document) return
  const head = document.querySelector('head')
  if (!head) return
  // title
  const title = document.querySelector('title')
  if (title) {
    document.title = headTags.title + titleSuffix
  } else {
    const title = document.createElement(HeadTag.title)
    title.text = headTags.title + titleSuffix
    head.appendChild(title)
  }
  // link
  headTags.links.forEach(setting => {
    const link = head.querySelector(`[rel="${setting.rel}"]`)
    if (link) {
      setting.href !== null
        ? link.setAttribute('href', setting.href)
        : head.removeChild(link)
      return
    }
    if (setting.href) {
      const link = document.createElement(HeadTag.link)
      link.setAttribute('rel', setting.rel)
      link.setAttribute('href', setting.href)
      setting.href && head.appendChild(link)
    }
  })
  // meta
  mergeMetas(headTags.metas).forEach(setting => {
    const meta =
      head.querySelector(`[name="${setting.name}"]`) ||
      head.querySelector(`[property="${setting.property}"]`)
    if (meta) {
      setting.content !== null
        ? meta.setAttribute('content', setting.content)
        : head.removeChild(meta)
      return
    }
    if (setting.content) {
      const meta = document.createElement(HeadTag.meta)
      if (setting.name) meta.setAttribute('name', setting.name)
      if (setting.property) meta.setAttribute('property', setting.property)
      meta.setAttribute('content', setting.content)
      setting.content && head.appendChild(meta)
    }
  })
}

enum HeadTag {
  title = 'title',
  link = 'link',
  meta = 'meta'
}

type HeadTags = {
  title: string
  links: Link[]
  metas: Meta[]
}

type Link = {
  rel: string
  href: string | null
}

type Meta = {
  name?: string
  property?: string
  content: string | null
}

```

## 使用例
```typescript
setHeadTags({
  title: 'タイトル',
  links: [
    { rel: 'canonical', href: 'https://sample.com' }
  ],
  metas: [
    { name: 'robots', content: 'noindex, nofollow' },
    { name: 'keyword', content: 'キーワード1,キーワード２' },
    { name: 'description', content: '説明' },
    { name: 'google-site-verification', content: '' },
    { property: 'og:url', content: 'https://sample.com' },
    { property: 'og:type', content: 'article' },
    { property: 'og:title', content: 'タイトル' },
    { property: 'og:description', content: '説明' },
    { property: 'og:site_name', content: 'サイト名' },
    { property: 'og:image', content: 'https://sample.com/image.png' }
  ]
})
```