Typescript infer type from default value

Viewed 27

How do I infer the type from a passed argument or default parameter

export type ParamList = {
  SignIn: { warningMessage?: string } | undefined
  ResetOrCreatePassword: { email: string; hasPasswordAssociated: boolean }
}

type Props = {
  text: string
  fallbackScreen?: keyof ParamList
  params?: ParamList[keyof typeof fallbackScreen] // not valid but shows the goal
}

function MenuLink({fallbackScreen = 'SignIn', params = undefined, ...rest}: Props) {
  // impl not important
}

// Cases that should work
MenuLink({ text: "Go to sign in" })

MenuLink({
  text: "Reset password",
  fallbackScreen: 'ResetOrCreatePassword', 
  params: {
    email: 'some@email.com',
    hasPasswordAssociated: true
  }
}) 

// TS should warn about missing params 
MenuLink({
  text: "Create password",
  fallbackScreen: 'ResetOrCreatePassword'
}) 
1 Answers

It is possible to achieve the desired behavior through the use of mapped types to generate the possible props:

type WithParams<T> = {
    [K in keyof T]: {
        text: string;
        fallbackScreen: K;
        params: T[K];
    }
}[keyof T];

type Props = {
    text: string;
    fallbackScreen?: never;
    params?: never;
} | WithParams<ParamList>;

This will give you something like this:

type Props = {
    text: string;
    fallbackScreen?: never;
    params?: never;
} | {
    text: string;
    fallbackScreen: "SignIn";
    params: { warningMessage?: string }
} | { ... }

You can see in the below playground that it also provides helpful errors.

Playground

Related