首页 > 解决方案 > 根据打字稿中的字符串文字缩小类型?

问题描述

我想输入一个 api 响应,其中资源在资源名称键上返回,即{ [resourceName]: resources, total: 10 }. 在以下示例中,根据请求的内容,我将如何键入响应对象来表示响应中存在apples或存在:oranges

interface Response {
    total: number
    apples: Array<object>
    oranges: Array<object>
}

const get = async (fruit: 'apples' | 'oranges') => {
    const data: Response = await fetchFruit(`https://example.com/${fruit}`)
    const count = data.total
    const applesOrOranges = data[fruit].filter(Boolean)
}

我必须对不同的可能响应使用联合类型,但我不清楚如何根据传递给函数的字符串文字来缩小联合类型:

interface Response {
    total: number
}
interface ApplesResponse extends Response {
    apples: Array<object>
}
interface OrangesResponse extends Response {
    oranges: Array<object>
}
type FruitResponse = ApplesResponse | OrangesResponse

const get = async (fruit: 'apples' | 'oranges') => {
    const data: FruitResponse = await fetchFruit(`https://example.com/${fruit}`)
    const count = data.total
    const applesOrOranges = data[fruit].filter(Boolean)
}

标签: typescript

解决方案


您可以使泛型 ( ) 的fruit参数并解析依赖于的返回类型:getKK

type FruitResponse = ApplesResponse | OrangesResponse
type FruitResponseKeys = 'apples' | 'oranges' // or extract it from the response types
type FruitResponseByKey<K extends FruitResponseKeys> = Extract<FruitResponse,{ [P in K]: any }>

const get = async <K extends FruitResponseKeys>(fruit: K): Promise<FruitResponseByKey<K>> => {
    // add validation logic for fetched data if you need that
    // we cast it here as any for brevity
    const data: FruitResponseByKey<K> = await fetch(`https://example.com/${fruit}`) as any
    const applesOrOranges = data[fruit].filter(Boolean)
    return { ...data, [fruit]: applesOrOranges }
}

const apples = get("apples") // Promise<ApplesResponse>
const oranges = get("oranges") // Promise<OrangesResponse>

FruitResponseByKey 基于. _ ApplesResponse_ _ _ _OrangesResponseFruitResponseK'apples' | 'oranges'

我认为,最有用的部分是,调用者根据fruit键获得正确的水果数组。由于fetch自然需要类型断言,我们只是any为了简单起见在函数体中使用。此外,其中的逻辑get没有任何复杂性,所以这应该很合适。

代码示例


推荐阅读