如何制作具有从参数类型推断出的返回类型的通用Typescript类型函数?

时间:2020-08-18 11:39:36

标签: typescript

我想将该模式重用于许多参数对象类型,并使函数的返回类型与对象类型的值相同

type IntentColorCategory = 'brand' | 'neutral' | 'semantic'
type IntentColor = 'primary' | 'secondary' | 'neutral' | 'error' | 'success'

// Understandably this doesn't work - intention is to have a function that
// has a return type corresponding to the value of the argument object
// values.
const getByIntentColorCategory<T extends any> = ({
  brand,
  neutral,
  semantic
}: Record<IntentColorCategory, T>) => (intent: IntentColor): T => {
  switch (intent) {
    case 'primary':
    case 'secondary':
      return brand;
    case 'neutral':
      return neutral;
    case 'error':
    case 'success':
    default:
      return semantic;
  }
}


// E.g.
getByIntentColorCategory<number>({ brand: 1, semantic: 2, neutral: 3 })
// I want to specify the object must have number values when used here and
//that the return type is a number

getByIntentColorCategory<string>({ brand: 'a', semantic: 'b', neutral: 'c' })
// I want to specify the object must have strings when used here and that
// the return type is a string

2 个答案:

答案 0 :(得分:1)

如果我正确理解了您的问题-我认为您只会受到放置通用参数的位置的困扰。它应该放在参数旁边(在函数侧,而不是在赋值侧)。

type IntentColorCategory = 'brand' | 'neutral' | 'semantic'
type IntentColor = 'primary' | 'secondary' | 'neutral' | 'error' | 'success'

const getByIntentColorCategory = <T extends any>({
  brand,
  neutral,
  semantic
}: Record<IntentColorCategory, T>) => (intent: IntentColor): T => {
  switch (intent) {
    case 'primary':
    case 'secondary':
      return brand;
    case 'neutral':
      return neutral;
    case 'error':
    case 'success':
    default:
      return semantic;
  }
}

您甚至可以在使用函数时删除显式类型参数:

enter image description here

答案 1 :(得分:0)

感谢@mbdavis,他的解决方案可以正常工作:

type IntentColorCategory = 'brand' | 'neutral' | 'semantic'
type IntentColor = 'primary' | 'secondary' | 'neutral' | 'error' | 'success'

const getByIntentColorCategory = <T extends any>({
  brand,
  neutral,
  semantic
}: Record<IntentColorCategory, T>) => (intent: IntentColor): T => {
  switch (intent) {
    case 'primary':
    case 'secondary':
      return brand;
    case 'neutral':
      return neutral;
    case 'error':
    case 'success':
    default:
      return semantic;
  }
}

type NumberIntents = Record<IntentColorCategory, number>
type StringIntents = Record<IntentColorCategory, string>

const numberIntents: NumberIntents = {
  brand: 1,
  neutral: 2,
  semantic: 3,
}

const stringIntents: StringIntents = {
  brand: 'a',
  neutral: 'b',
  semantic: 'c',
}

getByIntentColorCategory(numberIntents); // returns number
getByIntentColorCategory(stringIntents); // returns string

TS playground link