libphonenumber-js icon indicating copy to clipboard operation
libphonenumber-js copied to clipboard

[TypeScript] Maybe use "const assertion" that could be available in typescript 3.4+

Open catamphetamine opened this issue 4 years ago • 1 comments

https://github.com/catamphetamine/libphonenumber-js/issues/392#issuecomment-859472890

As @maurer2 suggested:

export const numberTypes = ['PREMIUM_RATE', 'TOLL_FREE', 'SHARED_COST', 'VOIP', 'PERSONAL_NUMBER', 'PAGER', 'UAN', 'VOICEMAIL', 'FIXED_LINE_OR_MOBILE', 'FIXED_LINE', 'MOBILE'] as const
export type NumberType = typeof numberTypes[number]

"NumberType basically stays the same but is now derived from a readonly tuple."

Whatever that meant.

TypeScript pros, leave your comments on that idea and whether it's compatible with the old TypeScript.

catamphetamine avatar Jun 13 '21 00:06 catamphetamine

Hello, here is a more detailed description of the feature: https://blog.logrocket.com/const-assertions-are-the-killer-new-typescript-feature-b73451f35802/

Cheers

maurer2 avatar Jun 16 '21 10:06 maurer2

I would find it useful if this library's type union definitions were exported as values (e.g. const arrays or enums).

In my TypeScript application I'm determining the country code of a user's location programmatically and I want to use that value with this library. That value comes from some other API and I'm not sure I can guarantee the country code I've determined matches the set of valid country codes defined in this library, so I wanted to check at runtime if a country code is valid and then fallback to a default value if it is not valid.

I found the set of country codes defined in types.d.ts. However I can't use this at runtime to check if a given string is valid because it's declared as a type, not a value. The suggestion here in https://github.com/catamphetamine/libphonenumber-js/issues/405#issue-919683480 or in https://github.com/catamphetamine/libphonenumber-js/issues/392#issuecomment-859472890 would help me in this scenario because I could compare my country code to the set of values.

Would you consider declaring and exporting the string union types as values for use cases such as mine? Or would you suggest an alternative approach for my use case?

lnhrdt avatar Feb 25 '23 23:02 lnhrdt

Hello, sounds like a good idea. Would probably look something like this for TS 4.9+ (not sure why there is a "001"):

export const countryCodes = ['001', 'AC', 'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AO', 'AR', 'AS', 'AT', 'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BR', 'BS', 'BT', 'BW', 'BY', 'BZ', 'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'EH', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'GA', 'GB', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GT', 'GU', 'GW', 'GY', 'HK', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IM', 'IN', 'IO', 'IQ', 'IR', 'IS', 'IT', 'JE', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KP', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK', 'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NC', 'NE', 'NF', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH', 'PK', 'PL', 'PM', 'PR', 'PS', 'PT', 'PW', 'PY', 'QA', 'RE', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'SS', 'ST', 'SV', 'SX', 'SY', 'SZ', 'TA', 'TC', 'TD', 'TG', 'TH', 'TJ', 'TK', 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'US', 'UY', 'UZ', 'VA', 'VC', 'VE', 'VG', 'VI', 'VN', 'VU', 'WF', 'WS', 'XK', 'YE', 'YT', 'ZA', 'ZM', 'ZW'] as const satisfies readonly string[];

export type CountryCode = typeof countryCodes[number];

maurer2 avatar Feb 25 '23 23:02 maurer2

@maurer2 & @catamphetamine, I found another approach used by another library that might be even better. The React component library mui-tel-input is based on libphonenumber-js. They generate a type called MuiTelInputCountry that is based on the countries defined in libphonenumber-js/metadata.min.json.

It seems like having the constant (not just the type) based off the source JSON data file would be easier to maintain and less prone to error than recreating and maintaining the list in TypeScript. Check it out the approach to generate the type here: https://github.com/viclafouch/mui-tel-input/blob/v3.1.1/src/shared/constants/countries.ts Perhaps the constant could be generated similar to this and included in libphonenumber-js itself.

CC: @viclafouch

lnhrdt avatar Feb 27 '23 20:02 lnhrdt

Thanks for the suggestions.

I'm not a TypeScript expert, but:

  • I've refactored type CountryCode to read from the JSON file, as @lnhrdt suggested
  • I didn't export const CountryCodes because it wouldn't import in an application anyway: I tested it with a simple application and import { CountryCodes } from 'libphonenumber-js' and it printed undefined from console.log(CountryCodes).
  • I don't see a point in having this issue open. There's no need to have a list of all possible phone number types. So I guess this issue can be closed.

@lnhrdt To test if a country code is valid, one could use the exported isSupportedCountry() function.

catamphetamine avatar Mar 15 '23 02:03 catamphetamine

Reverted the change because of https://gitlab.com/catamphetamine/libphonenumber-js/-/issues/94

catamphetamine avatar Mar 15 '23 05:03 catamphetamine