Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript make one parameter type depend on the other parameter

Say I have

interface Action<T> {
    assignAction(key: keyof T, value: any): void;
}

Say T is of type

{
    users: User[];
    accounts: Account[];
}

Now, when calling assignAction, let's say I want to pass users. So this action is false because types don't match:

assignAction('users', accounts)

I don't know how to validate value, since its type depends on what you choose for key.

like image 865
Kousha Avatar asked Jan 12 '18 18:01

Kousha


2 Answers

You should be able to add a generic to the assignAction function to help describe this relationship.

interface Action<T> {
    assignAction<K extends keyof T>(key: K, value: T[K]): void;
}

Then once your Action instance is given a generic type it knows how to associate the relationship between key and value when you call assignAction

like image 183
casieber Avatar answered Nov 17 '22 20:11

casieber


interface TypeA {
    objectIdA: string
}

interface TypeB {
    objectIdB: string
}

interface TypeC {
    objectIdC: string
}

enum Param1 {
    TypeA = "TypeA",
    TypeBC = "TypeBC"
}



type INamespaceKeyMap =
    & Record<Param1.TypeA, TypeA>
    & Record<Param1.TypeBC, TypeB | TypeC>;

type INamespaceKeys<T extends Param1.TypeA | Param1.TypeBC> = INamespaceKeyMap[T];

function test<NS extends Param1, Key extends INamespaceKeys<NS>>(namespace: NS, key: Key) {
    console.log("Called");
}

const objectA = {
    objectIdA: "test"
} as TypeA;

const objectB = {
    objectIdB: "test"
} as TypeB;

const objectC = {
    objectIdC: "test"
} as TypeC;

test(Param1.TypeA, objectB) // not allowed
test(Param1.TypeA, objectA)
test(Param1.TypeBC, objectA) // not allowed
test(Param1.TypeBC, objectB)
test(Param1.TypeBC, objectC)

like image 25
Nishant Kumar Avatar answered Nov 17 '22 20:11

Nishant Kumar