Home > Software design >  Returning type based on a string parameter used as keyof a Record type
Returning type based on a string parameter used as keyof a Record type

Time:07-17

I have state type as follows


type RootState = {
    car: Car[],    
    user: User[],
    driver: Driver[],
}

const state: RootState = {
    car: [{name: "Car1", brand: "Ford"}, {name: "Car2", brand: "Chevvy"}],
    driver: [{name: "joe", age: "3"}, {name: "carl", age: "4"}],
    user: [{name: "Hank", money: 1300}]
}

I am writing a method that accepts the name as the first parameter and on the basis of the given name, it determines the return type automatically.

It should know that if it is given car as the first parameter, state[type] would be an array of Cars and thus, should return a car

function getResourceAtIndex(type: keyof RootState, index: number){
    return state[type][index]
}

const car = getResourceAtIndex("car", 0)//Return types is Car |User|Driver instead of just car




type Car= {
    name: string,
    brand: string,
}
type User= {
    name: string,money: number
}
type Driver= {
    name: string, age: string
}
type RootState ={
    car: Car[],    
    user: User[],
    driver: Driver[],


}

const state: RootState = {
    car: [{name: "Car1", brand: "Ford"}, {name: "Car2", brand: "Chevvy"}],
    driver: [{name: "joe", age: "3"}, {name: "carl", age: "4"}],
    user: [{name: "Hank", money: 1300}]
}
function getResourceAtIndex<R>(type: keyof RootState, index: number){
    return state[type][index]
}
const car = getResourceAtIndex("car", 0)

CodePudding user response:

If you want the type checker to keep track of the literal type of the argument you pass in for the type parameter to getResourceAsIndex, then you need a more specific type than keyof RootState. To do so, you probably want to make that function generic in the type K of state, where K is constrained to keyof RootState:

function getResourceAtIndex<K extends keyof RootState>(
    type: K, index: number
): RootState[K][number] {
    return state[type][index]
}

You also need to annotate the return type of the function as RootState[K][number] to explicitly say you'd like a generic indexed access type as opposed to the inferred RootState[keyof RootState][number].

Now things work as you want:

const car = getResourceAtIndex("car", 0);
// const car: Car

Playground link to code

  • Related