catamphetamine / libphonenumber-js

A simpler (and smaller) rewrite of Google Android's libphonenumber library in javascript
https://catamphetamine.gitlab.io/libphonenumber-js/
MIT License
2.79k stars 216 forks source link

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

Closed catamphetamine closed 1 year ago

catamphetamine commented 3 years ago

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.

maurer2 commented 3 years ago

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

Cheers

lnhrdt commented 1 year ago

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?

maurer2 commented 1 year ago

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];

lnhrdt commented 1 year ago

@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

catamphetamine commented 1 year ago

Thanks for the suggestions.

I'm not a TypeScript expert, but:

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

catamphetamine commented 1 year ago

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