0

I'm not sure if the title describes my situation properly so I'd appreciate any edits in case there's a better way to phrase it.

I have a helper function that takes in a Database model and allows for the searching of rows in the Database table that belongs to the model.

It can be simplified as having three parameters, the database model, a search phrase, and the fields (columns) in which to look for the search phrase.

Right now I'm using a generic type called ModelAttributes in order to dynamically determine which fields are allowed to be passed to the fields property of the search function like so:

type ModelAttributes<SpecificModel> = {
  // First filter only keys that are strings
  [Field in keyof SpecificModel]: SpecificModel[Field] extends string
    ? // Of the string based keys, if they are generic to the Model type ignore them
      Field extends keyof Model
      ? never
      : Field
    : never;
}[keyof SpecificModel];

type SmartSearchParams<SpecificModel extends StandardModel> = {
  search: string;
  model: SpecificModel;
  fields: ModelAttributes<SpecificModel>[];
};

The problem is that I want the function to also have another parameter called associatedModels of the following type:

type AssociatedQueryTypes<AssociatedModel> = {
    model: AssociatedModel,
    fields: ModelAttributes<AssociatedModel>
}

Now you can pass a parameter called associatedModels with an array of the AssciatedQueryTypes and it should also validate that any fields used there belong to the model that was passed alongside it as well.

The problem arises because I don't know how to properly add the new type to the SmartSearchParams type.

I've tried the following:

type SmartSearchParams<SpecificModel extends StandardModel> = {
  search: string;
  model: SpecificModel;
  fields: ModelAttributes<SpecificModel>[];
  associatedModels: AssociatedQueryTypes<any>[]; // The 'any' is a problem
};

Now when I try to use the function it doesn't actually validate that the fields in the associatedModels parameter belong to the model that was passed alongside it, likely because of the any keyword. Is there any way around this?

1 Answer 1

1

Use another generic parameter:

type SmartSearchParams<SpecificModel extends StandardModel, AssociatedModels extends StandardModel[]> = {
  search: string;
  model: SpecificModel;
  fields: ModelAttributes<SpecificModel>[];
  associatedModels: (AssociatedModels[number])[];
};

function coolestFunctionEver<
  SpecificModel extends StandardModel,
  AssociatedModels extends StandardModel[],
>(
  smartSearchParams: SmartSearchParams<SpecificModel, AssociatedModels>,
  associateModels: AssociatedModels,
) {
  ...
}

We use (AssociatedModels[number])[] because if a tuple is passed ([Foo, Bar]) for example it would require you to use [Foo, Bar] when passing the models. However if we use [number] and wrap it back into an array, we get `(Foo | Bar)[] which is more desirable.

Sign up to request clarification or add additional context in comments.

4 Comments

The problem here is that it only accepts one type of model in the array for associatedModels. If my first associated model is Receipt for instance then the next model in the array is also required to be Receipt and I can't, for instance also include the Address model
I edited my answer to use a tuple/array for associatedModels instead; I must've missed that it was an array somehow!
This is exactly the piece of knowledge that I was missing. Thanks so much!
Nevermind, after some more testing, this doesn't solve the issue. Still, thanks for trying

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.