我正在尝试输入search endpoint of Spotify's API。
在他们的文档中,它说返回的有效载荷是
export enum ResourceType {
Album = 'album',
Artist = 'artist',
Playlist = 'playlist',
Track = 'track',
Show = 'show',
Episode = 'episode',
Audiobook = 'audiobook',
Albums = 'albums',
Artists = 'artists',
Playlists = 'playlists',
Tracks = 'tracks',
Shows = 'shows',
Episodes = 'episodes',
Audiobooks = 'audiobooks',
}
interface ResourceTypeToResultKey {
[ResourceType.Album]: ResourceType.Albums
[ResourceType.Artist]: ResourceType.Artists
[ResourceType.Track]: ResourceType.Tracks
[ResourceType.Playlist]: ResourceType.Playlists
[ResourceType.Show]: ResourceType.Shows
[ResourceType.Episode]: ResourceType.Episodes
[ResourceType.Audiobook]: ResourceType.Audiobooks
}
// Basically translates to -> Make every property possibly undefined
type SearchResults = {
[K in SearchType as ResourceTypeToResultKey[K]]?: unknown // Don't pay attention to the value, I got it fine.
}
但是,文档建议响应的真实的类型是:* “我们只会归还您要求的钥匙”*。
这就意味着:如果列表是文字类型,我们可以缩小类型并使属性成为必需的。
现在我的问题是:如果列表不是一个文字类型,我们如何强制响应仍然返回整个类型,所有属性都标记为可选?
基本上,我想做的是:
declare const search: <T extends SearchType>(types: T[]) => Required<Pick<SearchResults, ResourceTypeToResultKey[T]>>
declare const types: SearchType[]
const result = search(types)
// the given type should be `SearchResults` (all properties marked optional)
result.tracks // Not ok, should be optional as it can't be determined for sure
const result2 = search([ResourceType.Track])
// the given type should be `{ tracks: unknown }`
result2.tracks // ok
这可行吗?
以下是我的尝试:Playground
1条答案
按热度按时间jxct1oxe1#
首先,让我们看看如何检查数组是否是元组(文字类型)。
不同之处在于数组类型的长度。在元组的情况下,它是一个有限的数字。我们先来看看:
1
扩展了number
,因为它是number
的子类型,但不是相反。使用数组/元组的示例:
因此,我们可以得出结论,如果数组的
length
是一个有限数,那么它是一个元组,否则它是一个数组,我们无法确定它的确切长度。让我们为此编写一个实用程序类型:注意,我们使用
readonly
修饰符来接受readonly
数组/元组,因为readonly
版本的数组/元组是该数组的超类型:在
search,
中,我们必须修改泛型参数T
,使其受readonly SearchType[]
而不是SearchType
的约束。此外,我们需要将T
转换为const类型参数,以防止编译器将数组类型扩展为原始数组。请注意,const type parameters
是在Typescript>= 5.0
中添加的,如果您有较低版本,则需要在将数组传入函数时使用constAssert。我们需要这些更改才能使用IsTuple
,添加readonly
的原因在前面已经提到过:我们将在indexed access中得到
T
的元素:为了避免代码重复,我们将使用inert关键字将pick的结果存储在推断参数
R
中:接下来,我们将看看
T
是否是一个元组,如果是,我们将使R
为非可选的,否则返回原样:我们准备好了:
测试:
链接到Playground