简体   繁体   中英

Mapped types in function arguments

I have a list of screens in a file:

file1.ts

export const LANDING = 'landing.Landing'
export const REGISTER = 'landing.Register'
export const LOGIN = 'landing.Login'

and a list of props for each screens in another file

file2.ts


type LandingProps = { foo: string }
type RegisterProps = { bar: number }
type LoginProps = { baz: object }

I want to create a navigate function in another file such as:

file3.ts

import { LANDING, REGISTER, LOGIN } from 'file1'
import { LandingProps, RegisterProps, LoginProps } from 'file2'

const screens = [LANDING, REGISTER, LOGIN] as const
type ScreenType = typeof screens[number]

type Props = LandingProps | RegisterProps | LoginProps

function navigate(screen: ScreenType, props: Props) {
    console.log('Navigation to screen ', screen)
    console.log('Props are: ', props)
}

How can I type the argument props so that the props match the corresponding ScreenType?

And on a side note, is it possible to create a type based on all the export from file1 without having to specify which?

In order to make the compiler restrict the type of props based on the type of screen , you need to give it a mapping. The easiest way to do that in your case is to make a dummy interface, since the types of props are already key-like:

interface ScreenPropsMapping {
  [LANDING]: LandingProps,
  [REGISTER]: RegisterProps,
  [LOGIN]: LoginProps
}

Because LANDING etc are const string literals, we can use them as computed keys in interfaces.

Then you give navigate() a generic signature like this:

function navigate<K extends keyof ScreenPropsMapping>(
  screen: K, props: ScreenPropsMapping[K]
) {


}

Here, K is constrained to be one of the keys of the mapping interface, and props is constrained to be the particular property type at that key:

navigate(LANDING, { foo: "" }); // okay
navigate(LANDING, { bar: 1 }); // error

As for your side note, if you really want a type to be the union of all the types of exported values in a module, you could do something like this:

import * as File1 from 'file1'
type File1Types = typeof File1[keyof typeof File1];
// type File1Types = "landing.Landing" | "landing.Register" | "landing.Login"

Okay, hope that helps; good luck!

Playground link to code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM