首页 > 解决方案 > 函数参数中的映射类型

问题描述

我在文件中有一个屏幕列表:

文件1.ts

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

以及另一个文件中每个屏幕的道具列表

文件2.ts


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

我想navigate在另一个文件中创建一个函数,例如:

文件3.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)
}

如何键入参数props以使道具与相应的 ScreenType 匹配?

顺便说一句,是否可以根据file1的所有导出创建一个类型,而不必指定哪个?

标签: typescript

解决方案


为了让编译器props根据 的类型来限制 的类型screen,你需要给它一个映射。在您的情况下,最简单的方法是制作一个虚拟接口,因为类型props已经类似于键:

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

因为LANDINGetc 是const字符串文字,我们可以将它们用作接口中的计算键

然后你给出navigate()一个这样的通用签名:

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


}

在这里,K被限制为映射接口的键之一,并且props被限制为该键处的特定属性类型:

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

至于您的旁注,如果您真的希望一个类型成为模块中所有导出值类型的联合,您可以执行以下操作:

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

好的,希望有帮助;祝你好运!

Playground 代码链接


推荐阅读