Skip to the content.

Destructuring

Generally it is operation when complex object split into pieces and assigned to variables

Tuples

const tuple: [string, number, boolean] = ["test", 1, true];

All elements

const [e1, b2, c3] = tuple;

taking only some of elements

const [firstOnly] = tuple;
const [, secondElement] = tuple;
const [first, , last] = tuple;

Not really convenient and easy to make “commas” mistake when trying to take only last element

const [, , last_only] = tuple;

In combination with spread operator could take part of tuple into another tuple

tail will be tuple: [number, boolean]

const [head, ...tail] = tuple;

Common use case: return multiple values from a function

const someValidation = (): [Object?, string[]?] => [{}];
const [result, maybeErrors] = someValidation();

For arrays destructuring looks the same

const numbersArray = [1, 2, 3, 4, 5];
const [arrayHead, ...arrayTail] = numbersArray;

Object destructuring

Allows to assign one or more values based on object properties

interface SplitIntoPieces {
  error: string;
  data: number;
  probably?: number;
}
const { error, data, probably } = {} as SplitIntoPieces;

Destructuring deep properties

interface DestroyMeDeep {
  message: string;
  data: {
    a: string;
    b: number;
  };
}
const {
  data: { a, b },
} = {} as DestroyMeDeep;

Destructuring with changing parameter name

const {
  message: someMessage,
  data: { a: aOther },
} = {} as DestroyMeDeep;

Destructuring: Common use case Provide Dependency container to your application and pick services when they needed

interface ApplicationConfig {
  database: Object;
  api: Object;
  logger: Object;
  config: Object;
}
const applicationConfigInstance = {
  database: {},
  api: {},
  logger: {},
  config: {},
};
const { api } = applicationConfigInstance;

Spread operator

In functions

It is opposite of destructuring

Spread of function arguments from the tuple. All parameters are required and tuple has fixed length, it is perfect match

const args: [number, number, string] = [1, 2, "3"];
function spreadTuple(a: number, b: number, c: string): void {}
spreadTuple(...args);

From an array.

Array has more elements, so remaining will be ignored.

Also due to array variable nature all function parameters should be optional and match type

const args2 = [1, 2, 3, 4];
function spreadAccept(a?: number, b?: number): void {}
spreadAccept(...args2);

Spread as function parameter

console.log is the most common example of this practice

function acceptAll(...strings: string[]): void {}
acceptAll("a", "b", "c");

In objects

Could add properties from one object into another (merge).

Usually used as alternative to Object.assign()

interface BaseProperties {
  a: number;
  b: number;
  c: number;
}
interface ExtendedProperties extends BaseProperties {
  run: () => void;
}
const dataObject = {
  a: 1,
  b: 2,
  c: 3,
};
const extendedDataObject: ExtendedProperties = {
  run: () => console.log("Running"),
  ...dataObject,
};

Important to keep spreads order.

Often used to define default values

const defaultUser = {
  name: "default name",
  email: "default email",
};
const apiRequestData = {
  name: "Test",
  age: 21,
};
const resultingUser = {
  userId: "abc",
  ...defaultUser,
  ...apiRequestData,
};

will result in:

const resultingUserShape = {
  userId: "abc",
  name: "Test",
  age: 21,
  email: "default email",
};

Spread deep properties

Each object should be specified explicitly like address here

interface DeepProperties {
  name: string;
  names: string[];
  age: number;
  address: {
    country: string;
    city: string;
    street: string;
  };
}
const userA: DeepProperties = {} as DeepProperties;
const userB: DeepProperties = {} as DeepProperties;

const resultingUserAB: DeepProperties = {
  ...userA,
  ...userB,
  // merge arrays manually
  names: [...userA.names, ...userB.names],
  // merge "deep" objects manually
  address: {
    ...userA.address,
    ...userB.address,
  },
};