Typescript 使用对象扩展来满足泛型联合类型。

huangapple go评论52阅读模式
英文:

Typescript using object spread to satisfy a generic union type

问题

result: {
  type: animalType,
  fedBy: byWhom,
  ...params,
},
英文:

Given a union type with common fields type and fedBy. I want to write a function that takes in an Animal as the type and a second argument with the params unique to that animal. I can get the signature and inference working, but doing something wrong in how to return the result.

type FeedAnimalParams =
  | {
      type: 'Dog'
      fedBy: string
      bowl: true
    }
  | {
      type: 'Cat'
      fedBy: string
      fish: string
    }
  | {
      type: 'Bird'
      fedBy: string
      seed: string
    }

I'm inferring a literal type, pulling out the type property

type Animal = FeedAnimalParams['type']
//type Animal = "Dog" | "Cat" | "Bird"

I'm pulling the unique fields required for each animal using a generic.

type UniqueAnimalParams<T extends Animal> = Omit<Extract<FeedAnimalParams, { type: T }>, 'type' | 'fedBy'>

type FeedResult<T> = {
  message: string
  result: T
}

Here's the function I'm trying to write

function feed<T extends Animal>(
  byWhom: string,
  animalType: T,
  params: UniqueAnimalParams<T>,
): FeedResult<FeedAnimalParams> {
  return {
    message: `Fed by ${byWhom}`,
    result: { //compile error here
      type: animalType,
      fedBy: byWhom,
      ...params,
    },
  }
}


//other lib
function CantChangeSignature(input:FeedAnimalParams){
  console.log(input)
} 

I get the intellisense when calling the function, so inference appears to be working but the function doesn't compile.


feed('Colin', 'Bird', {
  seed: 'Sunflower',
})

feed('Joe', 'Dog', {
  bowl: true,
})

Playground link

Edit:1
Trying to avoid changing the return type signature since I need to pass it into another function I can't change.

FeedResult<FeedAnimalParams>

//also tried this as the return type

FeedResult<Extract<FeedAnimalParams, {type:T}>>

Updated playground.

答案1

得分: 1

function feed(
byWhom: string,
animalType: T,
params: UniqueAnimalParams,
): FeedResult<UniqueAnimalParams & {type: T, fedBy: string}> {
return {
message: Fed by ${byWhom},
result: {
type: animalType,
fedBy: byWhom,
...params,
},
}
}

英文:

You need to relate to the return type to the generic otherwise TS can't make the return value to be specific to the passed animalType so it thinks it's all of them all at once.

function feed&lt;T extends Animal&gt;(
  byWhom: string,
  animalType: T,
  params: UniqueAnimalParams&lt;T&gt;,
): FeedResult&lt;UniqueAnimalParams&lt;T&gt; &amp; {type: T, fedBy: string}&gt;   {
  return {
    message: `Fed by ${byWhom}`,
    result: {
      type: animalType,
      fedBy: byWhom,
      ...params,
    },
  }
}

huangapple
  • 本文由 发表于 2023年2月18日 07:06:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/75489991.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定