最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

typescript - Narrow generic type in switch branch - Stack Overflow

programmeradmin2浏览0评论

I have a event map typed out like so:

type Amount = number

export type EventMap = {
  'player:modifyCredits': Amount
  'player:modifyEnergy': Amount
  'player:die': void
}

In a function I have a create a string representation for an occurred event:

export function actionEffectToLabel<K extends keyof EventMap = keyof EventMap>(effect: [K, EventMap[K]]) {
  const [key, value] = effect

  switch (key) {
    case 'player:modifyEnergy':
      return value > 0 ? `+ energy` : `- energy`
    case 'player:modifyCredits':
      return value > 0 ? `+${value} credits` : `${value} credits`
    default:
      return undefined
  }
}

But TypeScript gives an error for the value comparison lines:

TS2365: Operator > cannot be applied to types EventMap[K] and number

I was under the impression that effect: [K, EventMap[K]] would tie the type of the value to the key once specified in the case branches. What I want is that once I test key to be player:modifyEnergy, the type system understands that value has to be Amount and therefore resolves to the type number. Is that possible?

I have a event map typed out like so:

type Amount = number

export type EventMap = {
  'player:modifyCredits': Amount
  'player:modifyEnergy': Amount
  'player:die': void
}

In a function I have a create a string representation for an occurred event:

export function actionEffectToLabel<K extends keyof EventMap = keyof EventMap>(effect: [K, EventMap[K]]) {
  const [key, value] = effect

  switch (key) {
    case 'player:modifyEnergy':
      return value > 0 ? `+ energy` : `- energy`
    case 'player:modifyCredits':
      return value > 0 ? `+${value} credits` : `${value} credits`
    default:
      return undefined
  }
}

But TypeScript gives an error for the value comparison lines:

TS2365: Operator > cannot be applied to types EventMap[K] and number

I was under the impression that effect: [K, EventMap[K]] would tie the type of the value to the key once specified in the case branches. What I want is that once I test key to be player:modifyEnergy, the type system understands that value has to be Amount and therefore resolves to the type number. Is that possible?

Share edited Mar 11 at 8:13 jonrsharpe 122k30 gold badges268 silver badges476 bronze badges asked Mar 11 at 8:02 Johannes KlaußJohannes Klauß 11.1k18 gold badges71 silver badges127 bronze badges 1
  • 1 No, the types of key/effect[0] and value/effect[1] are independent (and they might be something like 'player:modifyCredits' | 'player:modifyEnergy' | 'player:die' and Amount | void respectively). What you'd need I think is a discriminated union where effect: ['player:modifyCredits', Amount] | ['player:modifyEnergy', Amount] | ['player:die' | void]. There's probably some way of using mapped types to generate that from EventMap. – Bergi Commented Mar 11 at 9:46
Add a comment  | 

1 Answer 1

Reset to default 1

If you make the generic parameter as the mapped type of EventMap, TS would treat effect as a discriminated union which is narrowed easily. Since the correlation is done inside the mapped type you don't need even a generic parameter and can set it directly on the argument too.

Playground

type Amount = number

export type EventMap = {
  'player:modifyCredits': Amount
  'player:modifyEnergy': Amount
  'player:die': void
}


export function actionEffectToLabel<T extends {[K in keyof EventMap]: [K, EventMap[K]]}[keyof EventMap]>(effect: T) {
  const [key, value] = effect;
  switch (key) {
    case 'player:modifyEnergy':
      return value > 0 ? `+ energy` : `- energy`
    case 'player:modifyCredits':
      return value > 0 ? `+${value} credits` : `${value} credits`
    default:
      return undefined
  }
}
发布评论

评论列表(0)

  1. 暂无评论