RecordOf and Type functions

Applies to: Canvas apps

Constructs a user defined type for use with user defined functions and untyped values.

Important

Description

Every function in Power Fx defines the types of values that can be passed in as parameters and the type of the output. Types are checked when you write a formula and errors shown if they don't agree with what is expected. Types are also used by the editor to suggest good options for what to pass into the function and detect errors as early as possible.

When creating your own user defined functions, you need to specify the input and output types. For simple types like Decimal or Text, this is easy as these basic types are predefined. For more complex types, such as records or tables, use the Type function to create the type.

The Type function also makes untyped objects easier to work with. With ParseJSON, IsType, and AsType functions, an untyped object can be converted to a typed object in which columns no longer need to be individually typed at the point of usage.

The Type function takes a TypeSpecification as its only argument. The simplest type specification is to reference an existing type, for example Type( Text ). A type specification for a record or table is similar to defining a record or table with literal values, where the values are replaced by type names. For example, {Name: "Jane"} would be typed with Type( {Name: Text} ). Tables are specified with square brackets, not the Table function, and only one record can be provided. For example, [1,2,3] would be typed with Type( [Number] ).

Use the RecordOf function to extract the record type from a table type. For example, Type( RecordOf( Library ) ) would return the type of a single book from the library. To make a table type from a record type, wrap the record type in square brackets. For example, Type( [ Book ] ) defines a library. RecordOf can only be used within the Type function.

The Type function and the type value it returns can only be used in specific places in Power Fx, such as the second argument to ParseJSON. In Canvas apps, the Type function can be used with a named formula in App.Formulas.

Syntax

RecordOf( TableType )

  • TableType – Required. The type name of a table. This doesn't accept a type specification, it needs to be the name of a previously defined type for a table.

Type( TypeSpecification )

  • TypeSpecification – Required. A type specification.

Examples

Type function

Consider the following definitions in App.Formulas:

Library = 
  [ { Title: "A Study in Scarlet", Author: "Sir Arthur Conan Doyle", Published: 1887 }, 
    { Title: "And Then There Were None", Author: "Agatha Christie", Published: 1939 },
    { Title: "The Marvelous Land of Oz", Author: "L. Frank Baum", Published: 1904 } ];

// Type definition for a single book
BookType := Type( { Title: Text, Author: Text, Published: Number } );

// Type definition for a table of books
LibraryType := Type( [ BookType ] );

Notice how the actual title text "A Study in Scarlet" is replaced with the type name Text in the type specification, a placeholder for any text value. A parameter or variable of type BookType can hold one of the books in Library, while LibraryType can hold the entire table. With these types in place, we can define these user defined functions:

SortedBooks( books: LibraryType ): LibraryType = 
    SortByColumns( Library, Author, SortOrder.Ascending, Title, SortOrder.Ascending );

PublishedInLeapYear( book: BookType ): Boolean = 
    Mod( book.Published, 4 ) = 0 And 
    (Mod( book.Published, 100 ) <> 0 Or Mod( book.Published, 400 ) = 0);

You can also use the BookType to parse a JSON string that contains a book:

ParseJSON( "{""Title"":""Gulliver's Travels"", ""Author"": ""Jonathan Swift"", ""Published"": 1900}", BookType
)

Using BookType as the second argument to ParseJSON results in a typed record that can be used like any other Power Fx record.

RecordOf function

In the Type function example, you start with BookType and build LibraryType by wrapping a table around it. We could have defined these types in reverse with:

// Type definition for a table of books
RecordOfLibraryType := Type( [ { Title: Text, Author: Text, Published: Number } ] );

// Type definition for a single book
RecordOfBookType := Type( RecordOf( RecordOfLibraryType ) );