Object property name as function argument with ensured type in Typescript

59 Views Asked by At

How to write definition of type in function argument which is one of object properties with same type?

For example I have object:

type Article = {
  name: string;
  quantity: number;
  priceNet: number;
  priceGross: number;
};

and want to write function which summarise price depending on price type property:

function summarise(article: Article, priceTypeProperty: NeededProperty) {
  return article[priceTypeProperty] * article.quantity;
}

How definition of NeededProperty should look like to ensure typescript that it's one of Article properties priceNet or priceGross and it is number type?

2

There are 2 best solutions below

0
Piotr Witkoś On BEST ANSWER

Previous answer by Yaman Abd is correct, but I found little more pretty solution:

Solution

type NeededType = keyof Pick<Article, 'priceNet' | 'priceGross'>;

Explanation

  • keyof makes string type from one of given object properties
  • Pick is utility type that helps to select properties from Article type. So we are ensured that property is included in Article object type.

This solution suggest properties which you can use while defining type NeededType.

Example

So proper example look like this:

type Article = {
  name: string;
  quantity: number;
  priceNet: number;
  priceGross: number;
};
    
type NeededType = keyof Pick<Article, 'priceNet' | 'priceGross'>;

function summarise(article: Article, priceTypeProperty: NeededType) {
  return article[priceTypeProperty] * article.quantity;
}
    
// Usage
const myArticle: Article = {
  name: "Example Article",
  quantity: 5,
  priceNet: 10,
  priceGross: 12
};
    
const totalPriceNet = summarise(myArticle, "priceNet"); // Works
const totalPriceGross = summarise(myArticle, "priceGross"); // Also works
    
const totalPriceGross = summarise(myArticle, "otherPrice"); // does not work
0
Yaman Abd On

To achieve this you could use keyof and a type constraint to make sure that the parameter is one of the valid key names in the Article type and must be (priceNet or priceGross) and its a number type

type Article = {
  name: string;
  quantity: number;
  priceNet: number;
  priceGross: number;
};

function summarise(article: Article, priceTypeProperty: keyof Article & ("priceNet" | "priceGross")) {
  return article[priceTypeProperty] * article.quantity;
}

// Usage
const myArticle: Article = {
  name: "Example Article",
  quantity: 5,
  priceNet: 10,
  priceGross: 12
};

const totalPriceNet = summarise(myArticle, "priceNet"); // Works
const totalPriceGross = summarise(myArticle, "priceGross"); // Also works

const totalPriceGross = summarise(myArticle, "otherPrice"); // does not work