1

please see code sample below- i'd like some typesafety around the type of array entries that resetHistory takes in, but it's not creating a type error where i'd like it to! appreciate any tips.

typescript playground link

type Params = {
  profile: { userId: string };
  homepage: undefined;
  settings: { tab: "password" | "profile" };
};

// naive attempt at typing the history arg
function resetHistory<K extends keyof Params>(
  history: { name: K; params: Params[K] }[]
) {
  // ...
}

resetHistory([
  { name: "homepage", params: undefined },
  { name: "profile", params: { userId: "1234" } },
  { name: "settings", params: { userId: "xxx" } }, // <-- i want this to be a typeerror, and only accept { tab: "password" | "profile" }
]);

1 Answer 1

3

What you need here is a union of all possible pairings. We can create that with a mapped type.

type HistoryEntry = {
  [K in keyof Params]: Params[K] extends undefined 
      ? { name: K; params?: undefined; }
      : { name: K; params: Params[K]; }
}[keyof Params]

For each key of the Params object, the acceptable value is an object with a name that matches that key and a params that matches the Params value for that key. That is { name: K; params: Params[K]; }.

I am adding a conditional check Params[K] extends undefined to allow you to omit the params entirely if they are undefined. So you can just pass { name: "homepage" }.

Our resetHistory function is no longer generic. It accepts an array where all entries are of type HistoryEntry.

function resetHistory( history: HistoryEntry[] ) {

This gives us all of the errors that we want:

resetHistory([
  { name: "homepage" }, // ok
  { name: "profile", params: { userId: "1234" } }, // ok
  { name: "settings" }, // error: params is missing
  { name: "settings", params: { userId: "xxx" } }, // error: tab is missing from params
  { name: "settings", params: { tab: "password" } } // ok
]);

Typescript Playground Link

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

Comments

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.