incorrect TypeScript definitions for TelephoneNumber, Extension, PhoneCode
See original GitHub issueEDIT: it turned there was serious downside with this change i proposed bellow
Problem
Currently PhoneCode (and TelephoneNumber and Extension) are defined using interface, like:
export interface PhoneCode extends String { }
meaning, that variables/fields of these types are treated as objects, not string primitives
(even tough typeof phoneCode === "string"
).
As a result variable of type PhoneCode can’t be assigned to variables/fields with string type:
import { getPhoneCode } from 'libphonenumber-js';
const phoneCode = getPhoneCode('EE');
const phoneCodeAsString: string = phoneCode;
// ERROR:^^^^^^^^^^^ TS2322: Type 'PhoneCode' is not assignable to type 'string'.
Expected behaviour
Should be able to asign PhoneCode (and TelephoneNumber and Extension) to ´string´.
Solution
Declare PhoneCode (and TelephoneNumber and Extension) using
export type XXX = string
instead of
export interface PhoneCode extends String { }
Just in case, I’m mentioning @RonNewcomb, because he created the initial TypeScript definitions file, and also @catamphetamine who has created Extension
type by following example of @RonNewcomb
Issue Analytics
- State:
- Created 6 years ago
- Reactions:2
- Comments:21 (13 by maintainers)
I would like to suggest potentially reopening this issue. Idiomatic Typescript favors just using the “string” type instead of extending “String”. Most people using Typescript will expect the simple string type. Extending String should be left to the user and not required for everyone having to use the library. In most cases, the rest of the program will expect to consume the value as a regular string type. You are making a big assumption that people need to know the difference between CountryCode and TelephoneNumber at the type level. If they do, it should be on them to enforce that.
The assignment needs a cast:
const phoneCodeAsString: string = <string>phoneCode;
The problem with Typescript’s
export type XXX = string
syntax is that the Intellisense of every IDE I’ve ever seen will show a var/property of type XXX as being of type string, not XXX. That largely defeats the purpose of typing it at all. (I believe the syntax doesn’t actually make a new type; it’s just a shortcut to save typing. Hence it doesn’t throw type mismatch errors.)The reason that requiring a cast is (IMHO) a good thing is such: If you have an Address1 type descended from string and a CustomerName type descended from string, and you assign a value of one to a property/var of the other, you want to get the compiler error that requires a cast, because they’re different types despite both being represented as string.
This problem is particularly acute with string manipulation libraries like this one. Strings in, strings out, did this string already go through the library or not, does the phone# format that that string is in match the format that this string function accepts… everything’s a damn string. You’re effectively working with untyped data since
string
is about as helpful in this context asany
.Making subtypes that appear in intellisense helps a lot with simple usability, and the occasional required cast, albeit annoying, can save a you a bug hunt or two next week.
But yeah I really wish Typescript would realize that
var supertypeVar = subtypeValue
is a valid no-cast-required assignment by OO rules.