如何为函数定义类型以仅接受映射到特定类型的参数类型?
问题
我要写一个函数,传入字段名就能检查该字段是否为必填项,要求这个函数只接受Config类型中对应配置包含required属性的字段名。目前我已经有一个可行方案——通过定义ValidationField类型来约束函数参数:
type Field = 'name' | 'surname' | 'age' | 'height' | 'school'; type ValidationField = Extract<Field, 'name' | 'surname'>; type RequiredConfig = {required?: boolean}; type ValidationConfig<T> = T extends ValidationField ? RequiredConfig : {}; type Config = { [K in Field]?: ValidationConfig<K> & {visible?: boolean}; } const config: Config = {name: {required: true, visible: true}, surname: {required: true, visible: true}, age: {visible: false}} const checkRequired = (field: ValidationField) => config[field]?.required
但现在的情况是,我无法访问ValidationField类型,只能用Config、ValidationConfig和RequiredConfig这几个类型,请问有没有办法实现同样的参数约束效果?比如能不能像下面这样通过条件类型来约束泛型参数:
const checkRequired = <T extends Field>(field: Config[Field] extends ...? T : never) => config[field]?.required
解决方案
完全可以实现,核心是通过TypeScript的条件类型+键遍历,从Config中直接过滤出对应值兼容RequiredConfig的字段名,不需要依赖ValidationField。
方案一:先提取合法字段类型,再用于函数参数
type Field = 'name' | 'surname' | 'age' | 'height' | 'school'; type RequiredConfig = {required?: boolean}; type ValidationConfig<T> = T extends any ? (Extract<keyof Config, T> extends 'name' | 'surname' ? RequiredConfig : {}) : {}; type Config = { [K in Field]?: ValidationConfig<K> & {visible?: boolean}; } const config: Config = {name: {required: true, visible: true}, surname: {required: true, visible: true}, age: {visible: false}} // 从Config中筛选出对应值包含required属性的字段 type ValidRequiredField = keyof { [K in keyof Config as Config[K] extends RequiredConfig ? K : never]: unknown } const checkRequired = (field: ValidRequiredField) => config[field]?.required
方案二:直接在函数泛型中做约束(更简洁)
不需要单独定义ValidRequiredField,直接在函数的泛型参数里完成过滤:
const checkRequired = <T extends keyof Config>( field: T extends (Config[T] extends RequiredConfig ? T : never) ? T : never ) => config[field]?.required
两种方案都能让checkRequired函数只接受name和surname作为参数,和原来依赖ValidationField的效果完全一致,且没有使用ValidationField类型。
内容的提问来源于stack exchange,提问作者Andyally
相关产品推荐
相关产品推荐

