How to make Generic Functions that accept a value or an object with certain properties in TypeScript?
Tags: typescript
Published: 2022-01-16 00:00:00

---
  title: How to make Generic Functions that accept a value or an object with certain properties in TypeScript?
  published: true
  tags: TypeScript
  date: Sun Jan 16 2022 05:30:00 GMT+0530 (India Standard Time)
  canonical_url: https://melvingeorge.me/blog/make-generic-functions-that-accepts-value-object-with-certain-properties-typescript
  cover_image: https://melvingeorge.me/_next/static/images/main-61d330bd2796e1430e3e4bf9b62f5aa0.jpg
  ---
  [Originally posted here!](https://melvingeorge.me/blog/make-generic-functions-that-accepts-value-object-with-certain-properties-typescript)
  
To make generic functions that accept a value or an object as a parameter but with certain properties, you have to use the `extends` keyword on the `generic type parameter` and add some constraints on the generic type parameter for the function in TypeScript.

### TL;DR

```ts
// an interface
interface ShouldHaveLengthProp {
  length: number;
}

// a generic function that returns the
// value of the `length` property of
// the object passed to it
// with constraints for generic parameter type
function getLength<Type extends ShouldHaveLengthProp>(data: Type): number {
  return data.length; // Valid ✅
}

// call the function
getLength(1); // Error ❌. Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.
getLength(true); // Error ❌. Argument of type 'boolean' is not assignable to parameter of type '{ length: number; }'.
getLength([1, 2, 3, 4]); // Valid ✅. Returns => 4
getLength(["Roy", "Lily"]); // Valid ✅. Returns => 2
getLength({ name: "John", length: 5 }); // Valid ✅. Returns => 5
```

For example, let's say we need to make a generic function where it will return the value of the `length` property of whatever type is passed to the function as an argument like this,

```ts
// a generic function that returns the
// value of the `length` property of
// the object passed to it
function getLength<Type>(data: Type): number {
  return data.length; // Error ❌. Property 'length' does not exist on type 'Type'.
}
```

If you want to know more on creating Generic functions in TypeScript, See the blog on [How to make Generic Functions that change return value type according to the parameter values type in TypeScript?](https://melvingeorge.me/blog/make-generic-function-changes-return-type-according-parameter-value-type-typescript).

As soon as you write the function code, the TypeScript compiler will start showing an error on accessing `data.length` saying that `Property 'length' does not exist on type 'Type'.`.

This is expected since the function can accept values of any kind of `type` and not all `type` in TypeScript has the `length` property attached to them. The `length` property is available to values of the `array`, `string`, and any `object` type with a property called `length` in it.

So what we need to do is add constraints to the `generic type parameter` using the `extends` keyword after the `generic type parameter` name and then add the constraints we need to add there.

It can be done like this,

```ts
// a generic function that returns the
// value of the `length` property of
// the object passed to it
// with constraints for generic parameter type
function getLength<Type extends { length: number }>(data: Type): number {
  return data.length; // Valid ✅
}
```

As you can see that we have added the constraint of `{length: number}` after the `extends` keyword. This will check the object that is passed to the `getLength` function for the `length` property which also has a type of `number`. Adding constraints is like an if conditional checking for the `generic type parameter` in TypeScript. Cool. Right!? 😃.

Now let's call the `getLength` function and try to call the funtion with various value types like this,

```ts
// a generic function that returns the
// value of the `length` property of
// the object passed to it
// with constraints for generic parameter type
function getLength<Type extends { length: number }>(data: Type): number {
  return data.length; // Valid ✅
}

// call the function
getLength(1); // Error ❌. Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.
getLength(true); // Error ❌. Argument of type 'boolean' is not assignable to parameter of type '{ length: number; }'.
getLength([1, 2, 3, 4]); // Valid ✅. Returns => 4
getLength(["Roy", "Lily"]); // Valid ✅. Returns => 2
getLength({ name: "John", length: 5 }); // Valid ✅. Returns => 5
```

As you can see that the first 2 function calls with `number` and `boolean` values types have error since both these type doesn't have the property of `length` in it and the last 3 functions with `array` and an `object` type are valid since both these values have the property of `length` attached to it.

For better readability let's write the `generic type parameter` constraint as a separate type called `ShouldHaveLengthProp` like this,

```ts
// an interface
interface ShouldHaveLengthProp {
  length: number;
}

// a generic function that returns the
// value of the `length` property of
// the object passed to it
// with constraints for generic parameter type
function getLength<Type extends ShouldHaveLengthProp>(data: Type): number {
  return data.length; // Valid ✅
}

// call the function
getLength(1); // Error ❌. Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.
getLength(true); // Error ❌. Argument of type 'boolean' is not assignable to parameter of type '{ length: number; }'.
getLength([1, 2, 3, 4]); // Valid ✅. Returns => 4
getLength(["Roy", "Lily"]); // Valid ✅. Returns => 2
getLength({ name: "John", length: 5 }); // Valid ✅. Returns => 5
```

We have successfully made a generic function that accepts an object with a certain property, in our case (the `length` property). Yay 🥳!

See the above code live in [codesandbox](https://codesandbox.io/s/make-generic-functions-that-accepts-value-object-with-certain-properties-typescript-xvu5q?file=/src/index.ts).

That's all 😃!

### Feel free to share if you found this useful 😃.

---