javascripttypescriptgenerics

TypeScript: Enforcing PK Type Consistency with Defined Keysets in Generic Interfaces


// interfaces.tsx
interface User {
  id: number | string;
  name: string | null;
}

// keysets.tsx
const userPK = ["id"];


// store.tsx
interface StoreState<T, PK extends Extract<keyof T, string | number>> {
  data: T
  update(pk: Pick<T, PK>, updatedItem: Partial<T>);
}

If I write this way, update's first argument requires both id and name. How can I enforece PK to be whatever defined in userPK?


Solution

  • Just use const userPK = ["id"] as const; and typeof userPK[number]:

    Playground

    // interfaces.tsx
    interface User {
      id: number | string;
      name: string | null;
    }
    
    // keysets.tsx
    const userPK = ["id"] as const;
    
    
    // store.tsx
    interface StoreState<T, PK extends Extract<keyof T, string | number>> {
      data: T
      update(pk: Pick<T, PK>, updatedItem: Partial<T>): void;
    }
    
    declare const store: StoreState<User, typeof userPK[number]>;
    
    store.update({
      id: 2
    },{
      id: '3'
    });