Skip to content

Продвинутое использование

Типы TypeScript

Все публичные типы экспортируются из корня пакета:

ts
import type { OS } from 'os-detect'

// OS — это строковое объединение:
// 'ios' | 'macos' | 'android' | 'windows' | 'linux' | 'chromeos' | 'unknown'

Сужение типа через getOS()

ts
import { getOS } from 'os-detect'
import type { OS } from 'os-detect'

const os: OS = getOS()

switch (os) {
  case 'ios':
  case 'android':
    console.log('Mobile device')
    break
  case 'windows':
  case 'macos':
  case 'linux':
  case 'chromeos':
    console.log('Desktop device')
    break
  case 'unknown':
    console.log('Unrecognised OS')
    break
}

TypeScript знает, что после switch все ветки исчерпаны — отдельный default не нужен, если вы обрабатываете 'unknown'.

Типы для React

useOS() возвращает OS. useIsWindows11() возвращает boolean | null. Оба полностью типизированы, дополнительные импорты не нужны.

Типы для Vue

useOS() возвращает Readonly<Ref<OS>>. useIsWindows11() возвращает Readonly<Ref<boolean | null>>.

ts
import type { OS } from 'os-detect'
import { useOS } from 'os-detect/vue'
import type { Ref } from 'vue'

const os: Readonly<Ref<OS>> = useOS()

Стратегия определения

Браузер

  1. navigator.userAgentData.platform (Chrome 90+ / Edge 90+) — современная подсказка о платформе без раскрытия высокоэнтропийных данных. Надёжна и не подделывается через переопределение userAgent.
  2. navigator.userAgent — устаревший запасной вариант для всех остальных браузеров (Firefox, Safari, старый Chrome). Регулярные выражения намеренно консервативны, чтобы избежать ложных срабатываний.

Для Windows 11 требуется дополнительный асинхронный вызов navigator.userAgentData.getHighEntropyValues(['platformVersion']) — он скрыт за detectIsWindows11() и никогда не вызывается автоматически.

Node.js

Читает process.platform, когда navigator отсутствует. На серверной стороне парсинг userAgent не выполняется. detectIsWindows11() динамически импортирует встроенный модуль os и разбирает номер сборки из os.release().

Кэширование

Результаты хранятся в переменных уровня модуля после первого вызова. Последующие вызовы возвращают кэшированное значение напрямую, без обращения к DOM или процессу. Это делает повторные вызовы в реактивных контекстах (функции рендера, computed-свойства) практически бесплатными.

Ограничения

Каждый детектор в конечном счёте опирается на navigator.userAgentData, navigator.userAgent (или process.platform в Node.js). Отсюда два структурных следствия:

  • Строки userAgent можно подделать через браузер, расширение или эмуляцию устройства в devtools. Криптографически проверить сообщённую платформу невозможно — относитесь к результатам как к подсказке для UX, а не как к границе безопасности.
  • navigator.userAgentData — движущаяся цель. Chromium постепенно замораживает/сокращает устаревшую строку navigator.userAgent и прячет больше деталей за опциональными высокоэнтропийными значениями. Firefox и Safari вообще не реализуют userAgentData, поэтому всегда используют запасной вариант с regex по строке UA. Будущие изменения в браузерах могут потребовать обновления паттернов — это свойственно определению на основе UA в целом, а не специфично для этой библиотеки.

Кэш и resetDetectionCache

ts
import { resetDetectionCache } from 'os-detect'

resetDetectionCache() // очищает все кэшированные результаты определения

Все функции detectIs*() и getOS() кэшируют свой результат после первого вызова (см. раздел «Кэширование» выше). В обычной вкладке браузера ОС никогда не меняется в течение сессии, поэтому обычно это не нужно. Функция существует для продвинутых случаев:

  • Долгоживущий процесс Node.js (например, главный процесс Electron), которому нужно переоценить process.platform после смены контекста.
  • Тестовые наборы, которые мокают navigator/process.platform в каждом тесте без повторного импорта модуля.

detectIsWindows11() не кэшируется — она всегда заново выполняет свою асинхронную проверку.