Options
All
  • Public
  • Public/Protected
  • All
Menu

Postcode.js

Validate & parse UK postcodes

CI codecov Dependencies Size Downloads Release Try postcode on RunKit

Utility methods for UK Postcodes, including validating the shape of a postcode, extracting postcode elements (like incodes, outcodes, areas and more).

Tested against ~1.7 million postcodes on ONSPD.

Features

Links

Guides

Getting Started

Installation

npm install postcode

Validate

import { isValid } from "postcode";

isValid("AA1 1AB"); // => true

Parse

Pass a string to parse. This will return a valid or invalid postcode instance which can be easily destructured.

Valid Postcode

ValidPostcode type definition

import { parse } from "postcode";

const {
  postcode,    // => "SW1A 2AA"
  outcode,     // => "SW1A"
  incode,      // => "2AA"
  area,        // => "SW"
  district,    // => "SW1"
  unit,        // => "AA"
  sector,      // => "SW1A 2"
  subDistrict, // => "SW1A"
  valid,       // => true
} = parse("Sw1A     2aa");

Invalid Postcode

InvalidPostcode type definition

const {
  postcode,    // => null
  outcode,     // => null
  incode,      // => null
  area,        // => null
  district,    // => null
  unit,        // => null
  sector,      // => null
  subDistrict, // => null
  valid,       // => false
} = parse("    Oh no, ):   ");

Type Guard

The TypeScript compiler can infer if you have a valid postcode type from parse by checking the valid attribute

import { parse } from "postcode";

const postcode = parse("SW1A 2AA");

if (postcode.valid) {
  // `postcode` adheres to the `ValidPostcode` interface
  processString(postcode.outcode.toLowerCase()); // TypeScript compiler knows `outcode` to be a string
  processString(postcode.subDistrict.toLowerCase()); // And it will throw errors on common gotchas (e.g. subdistrict can be `null` on a valid postcode)
} else {
  // `postcode` adheres to the `InvalidPostcode` interface
  processInvalidPostcode(postcode);
}

Valid Postcode Object

Postcode .outcode .incode .area .district .subDistrict .sector .unit
AA9A 9AA AA9A 9AA AA AA9 AA9A AA9A 9 AA
A9A 9AA A9A 9AA A A9 A9A A9A 9 AA
A9 9AA A9 9AA A A9 null A9 9 AA
A99 9AA A99 9AA A A99 null A99 9 AA
AA9 9AA AA9 9AA AA AA9 null AA9 9 AA
AA99 9AA AA99 9AA AA AA99 null AA99 9 AA

Exported Methods

If you're just after a single value, you can import a single method.

Validation

isValid("Sw1A 2aa"); // => true

Formatting

import {
  toNormalised,
  toOutcode,
  toIncode,
  toArea,
  toDistrict,
  toSubDistrict,
  toSector,
  toUnit,
} from "postcode";

toNormalised("Sw1A 2aa");  // => "SW1A 2AA"
toOutcode("Sw1A 2aa");     // => "SW1A"
toIncode("Sw1A 2aa");      // => "2AA"
toArea("Sw1A 2aa");        // => "AA"
toDistrict("Sw1A 2aa");    // => "SW1"
toSubDistrict("Sw1A 2aa"); // => "SW1A"
toSector("Sw1A 2aa");      // => "SW1A 2"
toUnit("Sw1A 2aa");        // => "AA"

Extract & Replace

match. Retrieve valid postcodes in a body of text

const matches = match("The PM and her no.2 live at SW1A2aa and SW1A 2AB"); // => ["SW1A2aa", "SW1A 2AB"]

// Perform transformations like normalisation using `.map` and `toNormalised`
matches.map(toNormalised); // => ["SW1A 2AA", "SW1A 2AB"]
matches.map(toOutcode); // => ["SW1A", "SW1A"]

// No matches yields empty array
match("Some London outward codes are SW1A, NW1 and E1"); // => []

replace. Replace postcodes in a body of text, returning the updated corpus and any matching postcodes

const { match, result } = replace("The PM and her no.2 live at SW1A2AA and SW1A 2AB");
// => match: ["SW1A2AA", "SW1A 2AB"]
// => result: "The PM and her no.2 live at  and "

// Add custom replacement
replace("The PM lives at SW1A 2AA", "Downing Street");
// => { match: ["SW1A 2AA"], result: "The PM lives at Downing Street" };

// No match
replace("Some London outward codes are SW1A, NW1 and E1");
// => { match: [], result: "Some London outward codes are SW1A, NW1 and E1" }

Version 5.0.0

5.0.0 brings changes which allows for better treeshaking and interopability with ES Modules. It also deprecates legacy class based APIs in favour of single purpose methods.

Breaking Changes

  • postcode no longer exports a class. Legacy new Postcode() functionality has been removed. Methods attached to Postcode are all available as named exports.
  • postcode no longer uses default exports. All exports are named. E.g.
    // In <= 4.0.0
    import Postcode from "postcode";
    Postcode.parse("SW1A 2AA");
    

// In >= 5.0.0 import { parse } from "postcode"; parse("SW1A 2AA");


In many cases, migration can be achieved by changing `import Postcode from "postcode"` to `import * as Postcode from "postcode"`, however this gives up treeshaking advantages.

### New Features

- `postcode` now exports a ES Module build
- Exports regular expressions
- `match` accepts a string and returns all valid postcodes
- `replace` accepts a string and replaces valid postcodes with an optional second argument. Default replacement text is empty string `""`

## Definitions

[See the postcode format guide](https://ideal-postcodes.co.uk/guides/uk-postcode-format/) for a glossary of postcode component terms.

## Notes

Postcodes cannot be validated just with a regular expression (however complex). True postcode validation requires having a full list of postcodes to check against. Relying on a regex will produce false postives/negatives.

[See the postcode validation guide](https://ideal-postcodes.co.uk/guides/postcode-validation) for an overview of the approaches and tradeoffs associated with postcode validation.

## Testing

```bash
npm test

License

MIT

Contains Ordnance Survey Data © Crown Copyright & Database Right

Index

Type aliases

InvalidPostcode

InvalidPostcode: { area: null; district: null; incode: null; outcode: null; postcode: null; sector: null; subDistrict: null; unit: null; valid: false }

Type declaration

  • area: null
  • district: null
  • incode: null
  • outcode: null
  • postcode: null
  • sector: null
  • subDistrict: null
  • unit: null
  • valid: false

ValidPostcode

ValidPostcode: { area: string; district: string; incode: string; outcode: string; postcode: string; sector: string; subDistrict: string | null; unit: string; valid: true }

Represents a valid postcode

Note that results will be normalised (i.e. correctly formatted), including postcode

Type declaration

  • area: string
  • district: string
  • incode: string
  • outcode: string
  • postcode: string
  • sector: string
  • subDistrict: string | null
  • unit: string
  • valid: true

Variables

Const AREA_REGEX

AREA_REGEX: RegExp = /^[a-z]{1,2}/i

Tests for the area section of a postcode

Const INCODE_REGEX

INCODE_REGEX: RegExp = /\d[a-z]{2}$/i

Tests for the inward code section of a postcode

Const OUTCODE_REGEX

OUTCODE_REGEX: RegExp = /^[a-z]{1,2}\d[a-z\d]?$/i

Tests for the outward code section of a postcode

Const POSTCODE_CORPUS_REGEX

POSTCODE_CORPUS_REGEX: RegExp = /[a-z]{1,2}\d[a-z\d]?\s*\d[a-z]{2}/gi

Test for a valid postcode embedded in text

Const POSTCODE_REGEX

POSTCODE_REGEX: RegExp = /^[a-z]{1,2}\d[a-z\d]?\s*\d[a-z]{2}$/i

Tests for a valid postcode

Const SPACE_REGEX

SPACE_REGEX: RegExp = /\s+/gi

Const UNIT_REGEX

UNIT_REGEX: RegExp = /[a-z]{2}$/i

Tests for the unit section of a postcode

Functions

Const isValid

  • isValid(postcode: string): boolean
  • Detects a "valid" postcode

    • Starts and ends on a non-space character
    • Any length of intervening space is allowed
    • Must conform to one of following schemas:
      • AA1A 1AA
      • A1A 1AA
      • A1 1AA
      • A99 9AA
      • AA9 9AA
      • AA99 9AA

    Parameters

    • postcode: string

    Returns boolean

Const match

  • match(corpus: string): string[]
  • Searches a body of text for postcode matches

    Returns an empty array if no match

    example
    // Retrieve valid postcodes in a body of text
    const matches = match("The PM and her no.2 live at SW1A2aa and SW1A 2AB"); // => ["SW1A2aa", "SW1A 2AB"]
    
    // Perform transformations like normalisation postcodes using `.map` and `toNormalised`
    matches.map(toNormalised); // => ["SW1A 2AA", "SW1A 2AB"]
    
    // No matches yields empty array
    match("Some London outward codes are SW1A, NW1 and E1"); // => []

    Parameters

    • corpus: string

    Returns string[]

Const parse

  • Returns a ValidPostcode or InvalidPostcode object from a postcode string

    example
    import { parse } from "postcode";
    
    const {
    postcode,    // => "SW1A 2AA"
    outcode,     // => "SW1A"
    incode,      // => "2AA"
    area,        // => "SW"
    district,    // => "SW1"
    unit,        // => "AA"
    sector,      // => "SW1A 2"
    subDistrict, // => "SW1A"
    valid,       // => true
    } = parse("Sw1A     2aa");
    
    const {
    postcode,    // => null
    outcode,     // => null
    incode,      // => null
    area,        // => null
    district,    // => null
    unit,        // => null
    sector,      // => null
    subDistrict, // => null
    valid,       // => false
    } = parse("    Oh no, ):   ");

    Parameters

    • postcode: string

    Returns ValidPostcode | InvalidPostcode

Const replace

  • replace(corpus: string, replaceWith?: string): ReplaceResult
  • Replaces postcodes in a body of text with a string

    By default the replacement string is empty string ""

    example
    // Replace postcodes in a body of text
    replace("The PM and her no.2 live at SW1A2AA and SW1A 2AB");
    // => { match: ["SW1A2AA", "SW1A 2AB"], result: "The PM and her no.2 live at  and " }
    
    // Add custom replacement
    replace("The PM lives at SW1A 2AA", "Downing Street");
    // => { match: ["SW1A 2AA"], result: "The PM lives at Downing Street" };
    
    // No match
    replace("Some London outward codes are SW1A, NW1 and E1");
    // => { match: [], result: "Some London outward codes are SW1A, NW1 and E1" }

    Parameters

    • corpus: string
    • Default value replaceWith: string = ""

    Returns ReplaceResult

Const toArea

  • toArea(postcode: string): null | string
  • Returns a correctly formatted area given a postcode

    Returns null if invalid postcode

    Parameters

    • postcode: string

    Returns null | string

Const toDistrict

  • toDistrict(postcode: string): null | string
  • Returns a correctly formatted district given a postcode

    Returns null if invalid postcode

    example
    toDistrict("AA9 9AA") // => "AA9"
    toDistrict("A9A 9AA") // => "A9"

    Parameters

    • postcode: string

    Returns null | string

Const toIncode

  • toIncode(postcode: string): null | string
  • Returns a correctly formatted incode given a postcode

    Returns null if invalid postcode

    Parameters

    • postcode: string

    Returns null | string

Const toNormalised

  • toNormalised(postcode: string): null | string
  • Returns a normalised postcode string (i.e. uppercased and properly spaced)

    Returns null if invalid postcode

    Parameters

    • postcode: string

    Returns null | string

Const toOutcode

  • toOutcode(postcode: string): null | string
  • Returns a correctly formatted outcode given a postcode

    Returns null if invalid postcode

    Parameters

    • postcode: string

    Returns null | string

Const toSector

  • toSector(postcode: string): null | string
  • Returns a correctly formatted sector given a postcode

    Returns null if invalid postcode

    Parameters

    • postcode: string

    Returns null | string

Const toSubDistrict

  • toSubDistrict(postcode: string): null | string
  • Returns a correctly formatted subdistrict given a postcode

    Returns null if no subdistrict is available on valid postcode Returns null if invalid postcode

    example
    toSubDistrict("AA9A 9AA") // => "AA9A"
    toSubDistrict("A9A 9AA") // => "A9A"
    toSubDistrict("AA9 9AA") // => null
    toSubDistrict("A9 9AA") // => null

    Parameters

    • postcode: string

    Returns null | string

Const toUnit

  • toUnit(postcode: string): null | string
  • Returns a correctly formatted unit given a postcode

    Returns null if invalid postcode

    Parameters

    • postcode: string

    Returns null | string

Const validOutcode

  • validOutcode(outcode: string): boolean
  • Returns true if string is a valid outcode

    Parameters

    • outcode: string

    Returns boolean