TypeScript - 使用专有参数键入函数的对象映射
Posted
技术标签:
【中文标题】TypeScript - 使用专有参数键入函数的对象映射【英文标题】:TypeScript - Typing an object map of functions with exclusive parameters 【发布时间】:2022-01-23 18:16:45 【问题描述】:这是一个我通过键保存函数的对象:
export const questSetHelper: [key in QuestSetHelper]: (player: Player, payload: FlagGender | FlagOrigin | FlagAdventure) => void =
'setGender': setGender,
'setOriginCircumstance': setOriginCircumstance,
'setAdventureCircumstance': setAdventureCircumstance
我将它们保存为字符串,以便于处理从前端到后端的传递字符串,这些字符串用于确定要运行的函数。每个函数只处理一种负载类型。
例如:
export const setOriginCircumstance = (player: Player, payload: FlagOrigin): void =>
if (player.quests['intro']?.flags)
player.quests['intro'].flags['origin_circumstance'] = payload
else
throw new Error('Quest: intro - failed setOriginCircumstance')
当所有这些都输入到string
时,我当然没有任何类型错误,但我希望显式输入每个函数参数。
问题
显然,每个函数最终都可以处理payload
的questSetHelper
类型之一,但我想假设每个函数都将被正确调用并传递正确的类型(即FlagGender
有效负载将始终转到setGender
)。
有没有更好的方法在不改变结构的情况下输入这个?
【问题讨论】:
你能依赖类型推断吗?它将为questSetHelper
分配一个正确、精确的类型。如果不是,请解释原因。 typescriptlang.org/play?#code/…
泛型也应该可以工作。
@Lesiak 似乎依靠推理效果很好。我之前一直在尽可能明确地写出所有代码风格和代码完整性,但似乎在某些情况下不明确输入有优势。
【参考方案1】:
我相信有两种选择:
依赖类型推断
这是对您的代码的一个小改动
export const setGender = (player: Player, payload: FlagGender): void =>
export const setOriginCircumstance = (player: Player, payload: FlagOrigin): void =>
export const setAdventureCircumstance = (player: Player, payload: FlagAdventure): void =>
export const questSetHelper =
'setGender': setGender,
'setOriginCircumstance': setOriginCircumstance,
'setAdventureCircumstance': setAdventureCircumstance
Playground - inference
使用显式类型确保所有 setter 具有正确的类型
在这种方法中,您从定义QuestFlags
开始。
之后,您使用Key Remapping in Mapped Types 生成具有适当名称的设置器:
interface QuestFlags
gender: FlagGender
originCircumstance: FlagOrigin
adventureCircumstance: FlagAdventure
type QuestFlagsSetters =
[K in keyof QuestFlags & string as `set$Capitalize<K>`]: (player: Player, payload: QuestFlags[K]) => void
;
export const questSetHelper: QuestFlagsSetters =
'setGender': setGender,
'setOriginCircumstance': setOriginCircumstance,
'setAdventureCircumstance': setAdventureCircumstance
Playground - Key remapping
我看到您将蛇形大小写用于属性名称,而将驼峰大小写用于设置器。这也很容易实现:
interface QuestFlags
gender: FlagGender
origin_circumstance: FlagOrigin
adventure_circumstance: FlagAdventure
type SnakeCaseToPascalCase<S extends string> =
S extends `$infer FirstWord_$infer Rest` ?
`$Capitalize<Lowercase<FirstWord>>$SnakeCaseToPascalCase<Rest>` :
Capitalize<Lowercase<S>>;
type QuestFlagsSetters =
[K in keyof QuestFlags & string as `set$SnakeCaseToPascalCase<K>`]: (player: Player, payload: QuestFlags[K]) => void
;
export const questSetHelper: QuestFlagsSetters =
'setGender': setGender,
'setOriginCircumstance': setOriginCircumstance,
'setAdventureCircumstance': setAdventureCircumstance
Playground - Key remapping with snake_case changed to camelCase
【讨论】:
以上是关于TypeScript - 使用专有参数键入函数的对象映射的主要内容,如果未能解决你的问题,请参考以下文章
强烈键入 react-redux 与 typescript 连接