My goal is to create a TypeScript library for educational purposes. To enhance the developer experience, I want TypeScript to automatically infer the string literal type from one of the arguments passed in a function that takes an array of objects.
For instance: Let's consider a fruit array object, which consists of objects with a 'name' property that stores a string value.
const fruitArray = [
{ name: "apple" },
{ name: "orange" },
{ name: "banana" }
]
type FruitArray = typeof fruitArray
Now, I have a function that accepts this array object as the first argument and the name of the fruit as the second argument.
function getFruitName<T extends FruitArray>(fruitArray: T, name:T[number]["name"]) { /** ... **/ }
When calling this function with the necessary arguments, it correctly identifies typeof name
as string
within the getFruitName
function.
getFruitName(fruitArray, "apple")
The 'name' argument can only be one of the values present in the name property of the fruit object. I wish for TypeScript to deduce that string into a string literal of those values,
// Typescript should infer type of name like this instead of string
type name = "apple" | "orange" | "banana"
I understand that I could achieve this by using as const
on the fruitArray
, but I prefer not to do so as it would impact the type safety while writing the array objects.
The desired developer experience with this function is for the user to input the array of objects containing a 'name' property as the first argument, and when they attempt to add the second argument, the available options should be limited to the values in the array object's name property.
Is this scenario possible? Any suggestions are appreciated.
Update:
One limitation faced when using as const
is the lack of type safety during the creation of the fruitArray
. This can be addressed through the use of the `satisfies` operator. However, I would prefer to handle the typing of name as string literals within the library itself to automate this process without requiring additional work from the user for type safety.
// Library Code
type Fruit = {name:string, age:number}
function getFruitName<T extends Fruit[]>(fruitArray: T, name:T[number]["name"]) { /** ... **/ }
// Using the library
const fruitArray:Fruit[] = [
{ name: "apple", age: 1 },
{ name: "orange", age: 2 },
{ name: "banana", age: 3 }
]
getFruitName(fruitArray, "") // Type inference from fruit Array
Modifications can be made to the library code itself to achieve this functionality.