I'd like to write a typescript function that accepts arguments like this:
myFunc([
{
initialValue: 6, // number
finalValue: 8 // number
},
{
initialValue: 'hello', // string
finalValue: 'goodbye' // string
}
])
But will fail if given this:
myFunc([
{
initialValue: 6, // number
finalValue: 'goodbye' // should fail because not a number!
}
])
It feels like the solution should entail generics, but generics that are generic within each array item, not generic across the whole array.
EDIT: I'd like a solution that works with ANY type of value, not just strings or integers. I will likely need to use this for classes/functions as well.
You can get something like this to work using generics and mapped types. We will use a type parameter to capture the actual type of the parameter (whatever that is, even if is does contain invalid initial/final pairs). We then transform this type to a new type where finalValue is typed according to the actual initialValue passed in. We use this new type in with an intersection in the parameter type. This will mean that the type of the parameter is inferred into the type parameter but checked against out transformed type:
type FinalValues<T extends Array<{ initialValue: any }>> = {
[P in keyof T]: T[P] extends { initialValue: infer I } ? { initialValue: I, finalValue: I }: never
}
function myFunc<T extends [{ initialValue: any }] | Array<{ initialValue: any }>>(v: T & FinalValues<T>): FinalValues<T> {
}
myFunc([
{
initialValue: 6, // number
finalValue: 8 // number
},
{
initialValue: 'hello', // string
finalValue: 'goodbye' // string
}
])
myFunc([
{
initialValue: 6, // number
finalValue: "string" // err
},
{
initialValue: 'hello', // string
finalValue: 1 // err
}
])
Play
You could also be a bit more creative and add a sort of custom error so that the the errors are more readable: Play
Solution is to define list element type as a sum type which member or two strings or two numbers.
type A = {
initialValue: number
finalValue: number
}
type B = {
initialValue: string
finalValue: string
}
type ListAB = (A | B) [] // type contains or A(two numbers) or B(two strings)
Now the array with the type ListAB is strictly typed by Sum A | B. Example usage:
function myFunc(list: ListAB) {
// implementation
}
// correct
myFunc([
{
initialValue: 6, // number
finalValue: 8 // number
},
{
initialValue: 'hello', // string
finalValue: 'goodbye' // string
}
])
// will have error
myFunc([
{
initialValue: 6, // number
finalValue: 'a' // string
},
{
initialValue: 1, // number
finalValue: 'goodbye' // string
}
])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With