Search code examples
javascripttypescriptfunctionobject-propertiestype-definition

Object property name as function argument with ensured type in Typescript


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?


Solution

  • 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