Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save andrewsantarin/cb45e6370c50aaabb374aaca34ae100f to your computer and use it in GitHub Desktop.
Save andrewsantarin/cb45e6370c50aaabb374aaca34ae100f to your computer and use it in GitHub Desktop.
Drop-in TypeScript support for the 'react-intl-tel-input' module

react-intl-tel-input

These type definitions will help you work with react-intl-tel-input in TypeScript while this library doesn't have official support for it.

Follow the development of baked-in types here: patw0929/react-intl-tel-input#346


Table of Contents


Versions Supported

>= 8

Live Example

Right here: https://codesandbox.io/s/serene-leakey-b8uph

How You Can Use This

Those of you who are familiar with TypeScript .d.ts files would already know how to get this done your own way, but for those who don't, well, here's one way to do it using create-react-app:

  1. Make an app.

    create-react-app react-intl-tel-input-example --typescript
  2. Use the tsconfig.json file I've sampled to configure TypeScript in your project.

  3. Add the type definition file to a @/types folder in /src, so that type definitions are located exactly in /src/@types/react-intl-tel-input/index.d.ts, like this:

    ├── node_modules
    ├── public
    ├── src
    │   ├── @types
    │   │   └── react-intl-tel-input
    │   │       └── index.d.ts
    │   ├── index.tsx
    │   └── styles.css
    ├── README.md
    ├── package.json
    ├── yarn.lock
    └── .gitignore
    
  4. Use the library for effect.

    import React from 'react';
    import IntlTelInput from 'react-intl-tel-input'; // You should have type definitions now!

Known Limitations

This gist doesn't include other exports react-intl-tel-input provides because I don't expect many people to need it. You'll need to add your own.

// These imports will work in JS but my drop-in support does not have TS type definitions for them.
import TelInput from 'react-intl-tel-input/dist/components/TelInput';
import AllCountries from 'react-intl-tel-input/dist/components/AllCountries';
declare module 'react-intl-tel-input' {
export type CountryData = {
/** Country name. */
name?: string
/** ISO 3166-1 alpha-2 code. */
iso2?: string
/** International dial code. */
dialCode?: string
/** Order (if >1 country with same dial code). */
priority?: number
/** Area codes (if >1 country with same dial code). */
areaCodes?: string[] | null
}
export type IntlTelInputProps = {
/**
* Container CSS class name.
* @default 'intl-tel-input'
*/
containerClassName?: string
/**
* Text input CSS class name.
* @default ''
*/
inputClassName?: string
/**
* It's used as `input` field `name` attribute.
* @default ''
*/
fieldName?: string
/**
* It's used as `input` field `id` attribute.
* @default ''
*/
fieldId?: string
/**
* The value of the input field. Useful for making input value controlled from outside the component.
*/
value?: string
/**
* The value used to initialize input. This will only work on uncontrolled component.
* @default ''
*/
defaultValue?: string
/**
* Countries data can be configured, it defaults to data defined in `AllCountries`.
* @default AllCountries.getCountries()
*/
countriesData?: CountryData[] | null
/**
* Whether or not to allow the dropdown. If disabled, there is no dropdown arrow, and the selected flag is not clickable.
* Also we display the selected flag on the right instead because it is just a marker of state.
* @default true
*/
allowDropdown?: boolean
/**
* If there is just a dial code in the input: remove it on blur, and re-add it on focus.
* @default true
*/
autoHideDialCode?: boolean
/**
* Add or remove input placeholder with an example number for the selected country.
* @default true
*/
autoPlaceholder?: boolean
/**
* Change the placeholder generated by autoPlaceholder. Must return a string.
* @default null
*/
customPlaceholder?: ((placeholder: string, seletedCountryData: CountryData) => string) | null
/**
* Don't display the countries you specify. (Array)
* @default []
*/
excludeCountries?: string[]
/**
* Format the input value during initialisation.
* @default true
*/
formatOnInit?: boolean
/**
* Display the country dial code next to the selected flag so it's not part of the typed number.
* Note that this will disable nationalMode because technically we are dealing with international numbers,
* but with the dial code separated.
* @default false
*/
separateDialCode?: boolean
/**
* Default country.
* @default ''
*/
defaultCountry?: string
/**
* GeoIp lookup function.
* @default null
*/
geoIpLookup?: (countryCode: string) => void
/**
* Don't insert international dial codes.
* @default true
*/
nationalMode?: boolean
/**
* Number type to use for placeholders.
* @default 'MOBILE'
*/
numberType?: string
/**
* The function which can catch the "no this default country" exception.
* @default null
*/
noCountryDataHandler?: (countryCode: string) => void
/**
* Display only these countries.
* @default []
*/
onlyCountries?: string[]
/**
* The countries at the top of the list. defaults to United States and United Kingdom.
* @default ['us', 'gb']
*/
preferredCountries?: string[]
/**
* Optional validation callback function. It returns validation status, input box value and selected country data.
* @default null
*/
onPhoneNumberChange?: (isValid: boolean, value: string, seletedCountryData: CountryData, fullNumber: string, extension: string) => void
/**
* Optional validation callback function. It returns validation status, input box value and selected country data.
* @default null
*/
onPhoneNumberBlur?: (isValid: boolean, value: string, seletedCountryData: CountryData, fullNumber: string, extension: string, event: React.FocusEvent<HTMLInputElement>) => void
/**
* Optional validation callback function. It returns validation status, input box value and selected country data.
* @default null
*/
onPhoneNumberFocus?: (isValid: boolean, value: string, seletedCountryData: CountryData, fullNumber: string, extension: string, event: React.FocusEvent<HTMLInputElement>) => void
/**
* Allow main app to do things when a country is selected.
* @default null
*/
onSelectFlag?: (currentNumber: string, seletedCountryData: CountryData, fullNumber: string, isValid: boolean) => void
/**
* Disable this component.
* @default false
*/
disabled?: boolean
/**
* Static placeholder for input controller. When defined it takes priority over autoPlaceholder.
*/
placeholder?: string
/**
* Enable auto focus
* @default false
*/
autoFocus?: boolean
/**
* Set the value of the autoComplete attribute on the input.
* For example, set it to phone to tell the browser where to auto complete phone numbers.
* @default 'off'
*/
autoComplete?: string
/**
* Style object for the wrapper div. Useful for setting 100% width on the wrapper, etc.
*/
style?: React.CSSProperties
/**
* Render fullscreen flag dropdown when mobile useragent is detected.
* The dropdown element is rendered as a direct child of document.body
* @default true
*/
useMobileFullscreenDropdown?: boolean
/**
* Pass through arbitrary props to the tel input element.
* @default {}
*/
telInputProps?: React.InputHTMLAttributes<HTMLInputElement>
/**
* Format the number.
* @default true
*/
format?: boolean
/**
* Allow main app to do things when flag icon is clicked.
* @default null
*/
onFlagClick?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void
}
export type IntlTelInputState = {
showDropdown: boolean
highlightedCountry: number
value: string
disabled: boolean
readonly: boolean
offsetTop: number
outerHeight: number
placeholder: string
title: string
countryCode: string
dialCode: string
cursorPosition: any
}
export default class IntlTelInput extends React.Component<IntlTelInputProps, IntlTelInputState> {
//#region Properties
wrapperClass: {
[key: string]: boolean
}
defaultCountry?: string
autoCountry: string
tempCountry: string
startedLoadingAutoCountry: boolean
dropdownContainer?: React.ElementType | ''
isOpening: boolean
isMobile: boolean
preferredCountries: CountryData[]
countries: CountryData[]
countryCodes: {
[key: string]: string[]
}
windowLoaded: boolean
query: string
selectedCountryData?: CountryData
// prop copies
autoHideDialCode: boolean
nationalMode: boolean
allowDropdown: boolean
// refs
flagDropDown: HTMLDivElement | null
tel: HTMLInputElement | null
// NOTE:
// The underscore.deferred package doesn't have known type definitions.
// The closest counterpart is jquery's Deferred object, which it claims to derive itself from.
// These two are equivalent if you log it in console:
//
// underscore.deferred
// var deferred = new _.Deferred()
//
// jquery
// var deferred = $.Deferred()
deferreds: JQuery.Deferred<any, any, any>[]
autoCountryDeferred: JQuery.Deferred<any, any, any>
utilsScriptDeferred: JQuery.Deferred<any, any, any>
//#endregion
//#region Methods
/**
* Updates flag when value of defaultCountry props change
*/
updateFlagOnDefaultCountryChange(countryCode?: string): void
getTempCountry(countryCode?: string): CountryData['iso2'] | 'auto'
/**
* set the input value and update the flag
*/
setNumber(number: string, preventFocus?: boolean): void
setFlagDropdownRef(ref: HTMLDivElement | null): void
setTelRef(ref: HTMLInputElement | null): void
/**
* select the given flag, update the placeholder and the active list item
*
* Note: called from setInitialState, updateFlagFromNumber, selectListItem, setCountry, updateFlagOnDefaultCountryChange
*/
setFlag(countryCode?: string, isInit?: boolean): void
/**
* get the extension from the current number
*/
getExtension(number?: string): string
/**
* format the number to the given format
*/
getNumber(number?: string, format?: string): string
/**
* get the input val, adding the dial code if separateDialCode is enabled
*/
getFullNumber(number?: string): string
/**
* try and extract a valid international dial code from a full telephone number
*/
getDialCode(number: string): string
/**
* check if the given number contains an unknown area code from
*/
isUnknownNanp(number?: string, dialCode?: string): boolean
/**
* add a country code to countryCodes
*/
addCountryCode(countryCodes: {
[key: string]: string[]
}, iso2: string, dialCode: string, priority?: number): {
[key: string]: string[]
}
processAllCountries(): void
/**
* process the countryCodes map
*/
processCountryCodes(): void
/**
* process preferred countries - iterate through the preferences,
* fetching the country data for each one
*/
processPreferredCountries(): void
/**
* set the initial state of the input value and the selected flag
*/
setInitialState(): void
initRequests(): void
loadCountryFromLocalStorage(): string
loadAutoCountry(): void
cap(number?: string): string | undefined
removeEmptyDialCode(): void
/**
* highlight the next/prev item in the list (and ensure it is visible)
*/
handleUpDownKey(key?: number): void
/**
* select the currently highlighted item
*/
handleEnterKey(): void
/**
* find the first list item whose name starts with the query string
*/
searchForCountry(query: string): void
formatNumber(number?: string): string
/**
* update the input's value to the given val (format first if possible)
*/
updateValFromNumber(number?: string, doFormat?: boolean, doNotify?: boolean): void
/**
* check if need to select a new flag based on the given number
*/
updateFlagFromNumber(number?: string, isInit?: boolean): void
/**
* filter the given countries using the process function
*/
filterCountries(countryArray: string[], processFunc: (iso2: string) => void): void
/**
* prepare all of the country data, including onlyCountries and preferredCountries options
*/
processCountryData(): void
handleOnBlur(event: React.FocusEvent<HTMLInputElement>): void
handleOnFocus(event: React.FocusEvent<HTMLInputElement>): void
bindDocumentClick(): void
unbindDocumentClick(): void
clickSelectedFlag(event: React.MouseEvent<HTMLDivElement, MouseEvent>): void
/**
* update the input placeholder to an
* example number from the currently selected country
*/
updatePlaceholder(props?: IntlTelInputProps): void
toggleDropdown(status?: boolean): void
/**
* check if an element is visible within it's container, else scroll until it is
*/
scrollTo(element: Element, middle?: boolean): void
/**
* replace any existing dial code with the new one
*
* Note: called from _setFlag
*/
updateDialCode(newDialCode?: string, hasSelectedListItem?: boolean): string
generateMarkup(): void
handleSelectedFlagKeydown(event: React.KeyboardEvent<HTMLDivElement>): void
/**
* validate the input val - assumes the global function isValidNumber (from libphonenumber)
*/
isValidNumber(number?: string): boolean
formatFullNumber(number?: string): string
notifyPhoneNumberChange(number?: string): void
/**
* remove the dial code if separateDialCode is enabled
*/
beforeSetNumber(number?: string, props?: IntlTelInputProps): string | undefined
handleWindowScroll(): void
handleDocumentKeyDown(event: KeyboardEvent): void
handleDocumentClick(event: MouseEvent): void
/**
* Either notify phoneNumber changed if component is controlled
*/
handleInputChange(event: React.FocusEvent<HTMLInputElement>): void
changeHighlightCountry(showDropdown: boolean, selectedIndex: number): void
loadUtils(): void
/**
* this is called when the geoip call returns
*/
autoCountryLoaded(): void
//#endregion
}
}
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"allowSyntheticDefaultImports": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"esModuleInterop": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react",
"typeRoots": [
"node_modules/@types",
"src/@types"
]
},
"include": [
"src"
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment