@desource/phone-mask

中文文档
2.1.0发布于 2026/11/07MITTypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 2万

QQ 超轻量级国际手机号码 formatter & 校验器,自动同步到Google libphone数字. 框架不可知核心库.

中文使用文档
文档目录29 节
  1. * 特性
  2. * 安装
  3. 导入路径
  4. 分发格式
  5. QQ 快速启动
  6. 显示格式
  7. 基本格式
  8. 与国别数据合作
  9. 多个遮罩变体
  10. 本地化的国名
  11. 工具函数
  12. 对照国家规则审定编号
  13. 后端处理的 Raw 数字
  14. 自定义 Regex + 元数据( 区域/ Carrier 前缀)
  15. 多租户:租户Id 默认国家+特定租户审定规则
  16. API 参考
  17. 类型
  18. 根条目导出
  19. Kit 子路径导出
  20. 使用大小写
  21. 自定义输入格式
  22. 电话号码验证
  23. 建设国家选择器
  24. 正在获取旗舰 Emojis
  25. 数据更新
  26. QQ 套装大小
  27. 有关软件包
  28. 许可证
  29. 捐款

@ desource/ phone- mask (英语)

核心TypeScript 库,用于用 Google 的 libphone 数字数据掩盖国际电话号码

npm version code coverage SonarCloud Ask CodeWiki Ask Context7 Ask DeepWiki license

框架-可知手机口罩库 与Google的libphone数字数据库保持最新.

升级到 2. 0. 0 之前,审查 1.7.0的移徙 用于断开更改和需要更新.

* 特性

  • 🌍 240多个国家 有准确的口罩和拨号码
  • 🔄 自动符号 从 Google 的 libphone 编号
  • 🪶 小声 - 根条目为 6.1 KB 变焦, 2.9 KB gziped, 2.3 KB brotli
  • 🌳 树能震动 ——只导入您需要的
  • 🔧 类型脚本 ——已打满字
  • 🎯 零依赖关系

* 安装

npm install @desource/phone-mask
# or
yarn add @desource/phone-mask
# or
pnpm add @desource/phone-mask

导入路径

根项包含国家元数据并遮盖数据. 显示格式化、低级格式化、输入处理、检测和工具辅助工具 kit 子路径.

import { MasksFullMapEn, type CountryKey } from '@desource/phone-mask';
import { formatPhone, createPhoneFormatter, formatDigitsWithMap } from '@desource/phone-mask/kit';

分发格式

包件进口采用未消减的无害环境管理或通用JS;应用程序捆绑商处理打树机和打树机。 两个条目都包含每个模块格式的TypeScript声明.

使用大小写根项Kit 条目
无害环境管理,包括本地浏览器模块dist/esm/index.jsdist/esm/kit.js
常见JSdist/phone-mask.cjsdist/kit.cjs
浏览器全局, 可读dist/phone-mask.umd.jsdist/kit.umd.js
浏览器全局, 已修改dist/phone-mask.umd.min.jsdist/kit.umd.min.js

对于没有构建步骤的浏览器使用,加载两个全局器,将国家数据与格式化帮助器合并:

<script src="https://cdn.jsdelivr.net/npm/@desource/phone-mask/dist/phone-mask.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@desource/phone-mask/dist/kit.umd.min.js"></script>
<script>
  const result = phoneMaskKit.formatDigitsWithMap(phoneMask.MasksBaseMap.US[0], '2025551234');
  console.log(result.display); // "+1 202-555-1234"
</script>

将两个 CDN URL 绑入生产中相同的软件包版本 。 UNPKG支持相同的文件路径.

QQ 快速启动

显示格式

import { formatPhone } from '@desource/phone-mask/kit';

formatPhone('+12345678888'); // '+1 234 567 8888'
formatPhone('2345678888', 'US', { code: false, flag: true }); // '🇺🇸 234 567 8888'

见 formatPhone 选项和支持的输入格式.

基本格式

import { MasksBaseMap, MasksMap } from '@desource/phone-mask';
import { formatDigitsWithMap } from '@desource/phone-mask/kit';

// Get US mask with country code prefix
const prefixUsMask = MasksBaseMap.US;
// ["+1 ###-###-####"]

// Format digits
const result = formatDigitsWithMap(prefixUsMask[0], '2025551234');
console.log(result.display); // "+1 202-555-1234"
console.log(result.map); // [-1, -1, -1, 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, 9]

// Get US mask without country code prefix
const usMask = MasksMap.US.mask;
// ["###-###-####"]

// Format digits without country code
const resultNoCode = formatDigitsWithMap(usMask[0], '2025551234');
console.log(resultNoCode.display); // "202-555-1234"
console.log(resultNoCode.map); // [0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, 9]

与国别数据合作

import { MasksFullMapEn, type MaskFull } from '@desource/phone-mask';

// Access country data
const us = MasksFullMapEn.US;

console.log(us.name); // "United States"
console.log(us.code); // "+1"
console.log(us.mask); // ["###-###-####"]
console.log(us.flag); // "🇺🇸"

多个遮罩变体

一些国家有多种口罩格式:

import { MasksFullMapEn } from '@desource/phone-mask';

const gb = MasksFullMapEn.GB;
console.log(gb.mask);
// [
//   "#### ######",
//   "### ### ####",
//   "## #### ####"
// ]

本地化的国名

import { MasksFullMap } from '@desource/phone-mask';

// Get localized names
const germanMap = MasksFullMap('de');
console.log(germanMap.US.name); // "Vereinigte Staaten"

const frenchMap = MasksFullMap('fr');
console.log(frenchMap.US.name); // "États-Unis"

工具函数

import { countPlaceholders, removeCountryCodePrefix, pickMaskVariant, extractDigits } from '@desource/phone-mask/kit';

// Count placeholder digits
const count = countPlaceholders('+1 ###-###-####');
// 10

// Remove country code prefix
const stripped = removeCountryCodePrefix('+1 ###-###-####');
// "###-###-####"

// Pick best mask variant for digit count
const variants = ['+44 #### ######', '+44 ### ### ####'];
const best = pickMaskVariant(variants, 10);
// "+44 #### ######"

// Extract only digits from string
const digits = extractDigits('+1 (202) 555-1234');
// "12025551234"

对照国家规则审定编号

使用 createPhoneFormatter() 对照特定国家的口罩变体验证长度.

以下的食谱接受当地编号或带有所选国家调用代码的国际编号. 它们缩短了超数数字,以便与框架输入相匹配。 使用 country.code 从电话值中删除已知的呼叫代码; removeCountryCodePrefix() 用于口罩模板.

import { MasksFullMapEn, type CountryKey } from '@desource/phone-mask';
import { createPhoneFormatter, extractDigits } from '@desource/phone-mask/kit';

function validateForCountry(input: string, id: CountryKey) {
  const country = MasksFullMapEn[id];
  const value = input.trim();
  if (!country || (value.startsWith('+') && !value.startsWith(country.code))) {
    return {
      digits: '',
      display: '',
      isComplete: false
    };
  }

  const formatter = createPhoneFormatter(country);
  const inputWithoutCode = value.startsWith(country.code) ? value.slice(country.code.length) : value;
  const digits = extractDigits(inputWithoutCode, formatter.getMaxDigits());

  return {
    digits,
    display: formatter.formatDisplay(digits),
    isComplete: formatter.isComplete(digits)
  };
}

validateForCountry('+1 (202) 555-1234', 'US');
// { digits: "2025551234", display: "202-555-1234", isComplete: true }
validateForCountry('+12025551234', 'US');
// { digits: "2025551234", display: "202-555-1234", isComplete: true }

后端处理的 Raw 数字

使用原始数字进行存储和运输。 只保留客户端格式化 .

import { MasksFullMapEn, type CountryKey } from '@desource/phone-mask';
import { createPhoneFormatter, extractDigits } from '@desource/phone-mask/kit';

function buildPhonePayload(input: string, id: CountryKey) {
  const country = MasksFullMapEn[id];
  const value = input.trim();
  if (!country || (value.startsWith('+') && !value.startsWith(country.code))) return null;

  const formatter = createPhoneFormatter(country);
  const inputWithoutCode = value.startsWith(country.code) ? value.slice(country.code.length) : value;
  const localDigits = extractDigits(inputWithoutCode, formatter.getMaxDigits());

  return {
    country: id,
    phoneDigits: localDigits, // canonical backend field
    phoneE164: `${country.code}${localDigits}` // optional: with dialing prefix
  };
}

自定义 Regex + 元数据( 区域/ Carrier 前缀)

将 Phone Mask 元数据与区域特定的regex 规则合并:

import { MasksFullMapEn, type CountryKey } from '@desource/phone-mask';
import { createPhoneFormatter, extractDigits } from '@desource/phone-mask/kit';

const tenantCarrierRules: Partial<Record<CountryKey, RegExp>> = {
  BR: /^(11|21|31)\d{8,9}$/,
  IN: /^(98|99)\d{8}$/
};

function validateWithCarrierRule(input: string, id: CountryKey): boolean {
  const country = MasksFullMapEn[id];
  const value = input.trim();
  if (!country || (value.startsWith('+') && !value.startsWith(country.code))) return false;

  const formatter = createPhoneFormatter(country);
  const inputWithoutCode = value.startsWith(country.code) ? value.slice(country.code.length) : value;
  const digits = extractDigits(inputWithoutCode, formatter.getMaxDigits());
  const carrierRule = tenantCarrierRules[id];

  if (!formatter.isComplete(digits)) return false;
  return carrierRule ? carrierRule.test(digits) : true;
}

多租户:租户Id 默认国家+特定租户审定规则

import { MasksFullMapEn, type CountryKey } from '@desource/phone-mask';
import { createPhoneFormatter, extractDigits } from '@desource/phone-mask/kit';

type TenantPolicy = {
  defaultCountry: CountryKey;
  prefixRule?: RegExp;
};

const TENANT_POLICIES: Record<string, TenantPolicy> = {
  acme: { defaultCountry: 'US', prefixRule: /^(202|303)\d{7}$/ },
  globex: { defaultCountry: 'GB', prefixRule: /^7\d{9}$/ }
};

function createTenantPhoneService(tenantId: string) {
  const policy = TENANT_POLICIES[tenantId] ?? { defaultCountry: 'US' as const };
  const id = policy.defaultCountry;
  const country = MasksFullMapEn[id];
  const formatter = createPhoneFormatter(country);

  return {
    defaultCountry: id,
    format(input: string) {
      const value = input.trim();
      if (value.startsWith('+') && !value.startsWith(country.code)) return input;
      const inputWithoutCode = value.startsWith(country.code) ? value.slice(country.code.length) : value;
      const digits = extractDigits(inputWithoutCode, formatter.getMaxDigits());
      return formatter.formatDisplay(digits);
    },
    validate(input: string) {
      const value = input.trim();
      if (value.startsWith('+') && !value.startsWith(country.code)) return false;
      const inputWithoutCode = value.startsWith(country.code) ? value.slice(country.code.length) : value;
      const digits = extractDigits(inputWithoutCode, formatter.getMaxDigits());
      const complete = formatter.isComplete(digits);
      const prefixOk = policy.prefixRule ? policy.prefixRule.test(digits) : true;
      return complete && prefixOk;
    }
  };
}

API 参考

类型

// Country ISO 3166-1 alpha-2 code
type CountryKey = 'US' | 'GB' | 'DE' | ... // 240+ countries

// Mask interfaces
interface MaskBase {
  id: CountryKey;
  mask: Array<string>;
}
interface Mask extends MaskBase {
  code: string;
}
interface MaskWithFlag extends Mask {
  flag: string;
}
interface MaskFull extends MaskWithFlag {
  name: string;
}
type MaskBaseMap = Record<CountryKey, Array<string>>;
type MaskMap = Record<CountryKey, Omit<Mask, 'id'>>;
type MaskWithFlagMap = Record<CountryKey, Omit<MaskWithFlag, 'id'>>;
type MaskFullMap = Record<CountryKey, Omit<MaskFull, 'id'>>;

根条目导出

导入掩码数据和国家类型 @desource/phone-mask。 。 。 .

MasksBaseMap 打开 MasksBase

基本国家口罩,包括国家代码前缀(轻量级版):

const MasksBaseMap: MaskBaseMap;
const MasksBase: MaskBase[];

使用这些来获取带有国家代码前缀的生口罩. 说明: 一些帮助者功能可能会期望没有国家代码的口罩.

MasksMap 打开 Masks

以国家代码作为单独财产的面具:

const MasksMap: MaskMap;
const Masks: Mask[];

MasksWithFlagMap 打开 MasksWithFlag

带有国家代码和旗帜的面具:

const MasksWithFlagMap: MaskWithFlagMap;
const MasksWithFlag: MaskWithFlag[];

MasksFullMapEn 打开 MasksFullEn

英文国名完整的国家数据:

const MasksFullMapEn: MaskFullMap;
const MasksFullEn: MaskFull[];

MasksFullMap(locale: string) 打开 MasksFull(locale: string)

获得带有本地化国名的完整国家数据:

function MasksFullMap(locale: string): MaskFullMap;
function MasksFull(locale: string): MaskFull[];

支持的地方数字 : en, (中文(简体) ), de, (中文(简体) ), fr, (中文(简体) ), es, (中文(简体) ), it, (中文(简体) ), pt, (中文(简体) ), ru, (中文(简体) ), zh, (中文(简体) ), ja, (中文(简体) ), ko还有更多.

getFlagEmoji(countryCode: CountryKey)

获取国家代码的旗下emoji :

function getFlagEmoji(countryCode: CountryKey): string;

Kit 子路径导出

进口材料、输入处理、检测和工具助手 @desource/phone-mask/kit。 。 。 .

// Count # placeholders in mask
function countPlaceholders(mask: string): number;

// Remove country code prefix from mask
function removeCountryCodePrefix(mask: string): string;

// Pick best mask variant for digit length
function pickMaskVariant(masks: string[], digitLength: number): string;

// Extract digits from any string
function extractDigits(value: string, maxLength?: number): string;

// Detect a complete international number from current masks
function detectCountryFromPhone(value: string): CountryKey | undefined;

// Format digits according to template
function formatDigitsWithMap(value: string, digits: string): { display: string; map: number[] };

detectCountryFromPhone 需要领导 +。它首先匹配精确的格式,然后返回到 呼叫代码和数字数 排除代码。 共享匹配使用调用代码生成的默认国家; 例如,未格式化 +1 数字默认为美国。 不支持的语法,未知的调用代码,以及 未匹配的长度返回 undefined检测使用口罩,而不是分配前缀或数字验证.

import { detectCountryFromPhone } from '@desource/phone-mask/kit';

detectCountryFromPhone('+7 123 456 7788'); // 'KZ': unique mask
detectCountryFromPhone('+71234567788'); // 'RU': shared length, default country
detectCountryFromPhone('1234567788'); // undefined: no international prefix

processPaste 返回可选选项 country 当检测成功时。 在 已返回 newDigits,不包括调用代码。 检测到的国际粘贴取代整个输入并放置 端部有护身符,而上所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出. 其他粘贴保持正常 选择和插入行为.

formatPhone(value, country?, options?)

使用国家口罩组格式化一个显示的电话号码,以空格分隔. 这个纯函数在浏览器和SSR期间有效. React, Vue, and Svelte再导出此功能,用于模板和JSX. 角质 PhonePipe 请各位代表出席。 每个框架一揽子方案也通过下列方式揭露了这一点: /core 子路径.

import { formatPhone, type PhoneFormatOptions } from '@desource/phone-mask/kit';

formatPhone('+12345678888'); // '+1 234 567 8888'
formatPhone('2345678888', 'US'); // '+1 234 567 8888'
formatPhone('+1 (234) 567-8888', 'US', { code: false }); // '234 567 8888'
formatPhone('+12345678888', 'US', { flag: true }); // '🇺🇸 +1 234 567 8888'
formatPhone('234 567 8888', 'US', { code: false, flag: true }); // '🇺🇸 234 567 8888'
interface PhoneFormatOptions {
  readonly code?: boolean; // Include the calling code; defaults to true.
  readonly flag?: boolean; // Prepend the flag emoji; defaults to false.
}

function formatPhone(
  value: string | null | undefined,
  country?: CountryKey | null,
  options?: PhoneFormatOptions
): string;

只有一个明确 + 调用代码被删除; 空位数字作为没有调用代码的数字处理. 通过这些值的ISO国家代码. 没有国家,检测需要完整的国际编号,并使用口罩形状,调用代码,长度. 共享匹配使用默认国家, 如 US +1;检测不检查区域代码分配。 过 undefined 或者说 null 作为将检测与选择相结合的国家.

被供应国在调用代码时优先,所以 formatPhone('+12345678888', 'CA', { flag: true }) 保留了加拿大国旗。 如果代码冲突, 成功检测优先 : formatPhone('+442079460958', 'US') 返回时 '+44 2079 460958',不成功的检测保留了原值.

保留了重要的领先零。 空的,只有白空间, null,以及 undefined 数值返回 ''。不支持的国家、无效字符、扩展和超过所选掩码长度的值保持不变。 该函数不会推断树干前缀或验证是否指定了数字. 将结果显示为文本, 如任何用户提供的值 .

使用大小写

自定义输入格式

import { MasksFullMapEn } from '@desource/phone-mask';
import { formatDigitsWithMap, extractDigits } from '@desource/phone-mask/kit';

function formatPhoneInput(value: string, countryCode: string = 'US') {
  const country = MasksFullMapEn[countryCode];
  const mask = country?.mask[0];
  if (!mask) return value;

  const digits = extractDigits(value);

  return `${country.code} ${formatDigitsWithMap(mask, digits).display}`;
}

// Usage
const formatted = formatPhoneInput('2025551234', 'US');
// "+1 202-555-1234"

电话号码验证

import { MasksFullMapEn } from '@desource/phone-mask';
import { countPlaceholders } from '@desource/phone-mask/kit';

function isValidPhoneLength(digits: string, country: string): boolean {
  const masks = MasksFullMapEn[country]?.mask;
  if (!masks) return false;
  const validLengths = masks.map((m) => countPlaceholders(m));

  return validLengths.includes(digits.length);
}

// Usage
isValidPhoneLength('2025551234', 'US'); // true (10 digits)
isValidPhoneLength('202555', 'US'); // false (too short)

建设国家选择器

import { MasksFullEn, type CountryKey, type MaskFull } from '@desource/phone-mask';

type CountryOption = Omit<MaskFull, 'mask'>;

function getCountryOptions(): CountryOption[] {
  return MasksFullEn.map((data) => ({
    id: data.id,
    name: data.name,
    code: data.code,
    flag: data.flag
  }));
}

// Usage
const countries = getCountryOptions();
// [
//   { id: 'US', name: 'United States', code: '+1', flag: '🇺🇸' },
//   { id: 'GB', name: 'United Kingdom', code: '+44', flag: '🇬🇧' },
//   ...
// ]

正在获取旗舰 Emojis

import { getFlagEmoji } from '@desource/phone-mask';

// Get flag emoji for country code
const flag = getFlagEmoji('US'); // "🇺🇸"

数据更新

库同步到 谷歌的手机号码 通过自动化工作流程。 要手动更新 :

pnpm gen

获取最新数据并重生 data.json。 。 。 . 此更新生成了软件包使用的元数据文件( U)src/data.json, (中文(简体) ), src/data.min.js,以及 src/data-types.ts) (中文(简体) ).

QQ 套装大小

将包装的包裹装入真正的消费者建筑中

消费者进口大小( 最小)击出布罗特利
import * as PhoneMask from '@desource/phone-mask'6.09 KB (韩语)2.86 KB (韩语)2.30 KB (韩语)
import { MasksFullMapEn } from '@desource/phone-mask'5.75 KB (韩语)2.67 KB (韩语)2.13 KB (韩语)
import * as Kit from '@desource/phone-mask/kit'13.28 KB (韩语)5.83 KB (韩语)4.90 千兆贝
import { createPhoneFormatter } from '@desource/phone-mask/kit'1.03 KB (韩语)0.59 KB (韩语)0.53 KB (韩语)
import { formatDigitsWithMap } from '@desource/phone-mask/kit'0.25 KB (韩语)0.21 千兆贝0.18 KB (韩语)
import { extractDigits } from '@desource/phone-mask/kit'0.08 KB (韩语)0.10 KB (韩语)0.08 KB (韩语)
import { getCountry } from '@desource/phone-mask/kit'5.84 KB (韩语)2.72 KB (韩语)2.18 KB (韩语)

根项包含国家元数据并遮盖数据. 使用 @desource/phone-mask/kit 当您需要显示格式化、低级格式化、输入处理、检测或工具辅助工具时。 依赖数据帮助者, 如 getCountry 包括口罩数据;纯formatter和输入助手树-震到小的独立捆绑.

许可证

麻省理工学院 2026 来源实验室

捐款

见 贡献指南 用于开发、测试和出版检查.


由 Q 制作 来源实验室

版本与发布记录

@desource/phone-mask 共发布 24 个版本,首次发布于 2025/11/04;过去 12 个月发布了 22 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.1.0latest2026/11/074 天前
2.0.02026/10/3111 天前
1.7.02026/10/101 个月前
1.6.42026/09/261 个月前
1.6.32026/09/082 个月前
1.6.22026/08/242 个月前

其他发布通道:internal-beta → 1.2.1-beta.2。

关于 @desource/phone-mask 的常见问题

@desource/phone-mask 是什么?

QQ 超轻量级国际手机号码 formatter & 校验器,自动同步到Google libphone数字. 框架不可知核心库.

如何安装 @desource/phone-mask?

在项目目录运行 npm install @desource/phone-mask,或使用 pnpm add / yarn add / bun add。

@desource/phone-mask 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@desource/phone-mask 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@desource/phone-mask 可以商用吗?

@desource/phone-mask 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@desource/phone-mask 的下载量有多少?

根据 npm 官方下载统计,@desource/phone-mask 在 2026/10/12 – 2026/11/10 这 30 天内被下载 20,428 次,日均约 681 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@desource/phone-mask 还在维护吗?

最新版本 2.1.0 发布于 2026/11/07(4 天前);至今共发布 24 个版本,其中过去 12 个月发布了 22 个;首次发布于 2025/11/04。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。