【发布时间】:2021-05-05 17:52:54
【问题描述】:
我们使用JSON:API 作为我们 API 的主要序列化模式。在不深入细节的情况下,它要求来自服务器的 JSON 响应具有顶级 data 属性,该属性可能包含单个实体或一组实体:
// Single item
{ "data": { "id": 1 } }
// Collection of items
{ "data": [
{ "id": 1 },
{ "id": 2 }
] }
我将此模式编码为 TypeScript 类型,因此我们可以正确键入 API 响应。这产生了以下结果:
// Attributes as the base type for our entities
type Attributes = Record<string, any>;
// Single resource object containing attributes
interface ResourceObject<D extends Attributes> {
attributes: D;
}
// Collection of resource objects
type Collection<D extends Attributes> = ResourceObject<D>[];
// Resource object OR collection, depending on the type of D
type ResourceObjectOrCollection<D extends Attributes | Attributes[]> = D extends Array<infer E>
? Collection<E>
: ResourceObject<D>;
// A response with a resource object or a collection of items of the same type
interface ApiResponse<T> {
data: ResourceObjectOrCollection<T>;
}
response 始终包含data 属性,该属性可以是单个resource object,也可以是资源对象的集合。
资源对象始终包含一个 attributes 属性,该属性包含任意实体属性。此处所有输入的目的是通过将实体接口作为通用 T 传递来传播属性结构,如下面的示例所示:
interface Cat {
name: string;
}
function performSomeApiCall<Ret>(uri: string): Ret {
return JSON.parse(''); // Stub, obviously
}
function single<T extends Attributes = Attributes>(uri: string): ApiResponse<T> {
return performSomeApiCall<ApiResponse<T>>(uri);
}
single 函数从返回单个实体的端点获取响应 - 例如,/api/cats/42。因此,通过传递Cat 接口,数据类型可以正确解析为单个资源对象:
const name: string = single<Cat>('/api/cats/42').data.attributes.name;
我们还可以定义一个返回多个实体的函数:
function multiple<T extends Attributes = Attributes>(uri: string): ApiResponse<T[]> {
return performSomeApiCall<ApiResponse<T[]>>(uri);
}
这个函数返回一个Ts的集合,所以下面的也是有效的:
const names: string[] = multiple<Cat>('/api/cats').data.map(item => item.attributes.name);
不的作用是什么,但是,定义一个直接检索单个实体属性的函数,这是我不明白的:
function singleAttributes<T extends Attributes = Attributes>(uri: string): T {
return single<T>(uri).data.attributes;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
类型 'Record
' 不能分配给类型 'T'。
'Record' 可分配给类型'T' 的约束,但'T' 可以用约束'Record ' 的不同子类型来实例化。 (2322)
为什么 Typescript 能理解 single 函数返回 T 的资源对象,而不是 singleAttributes?在某个地方,它似乎放弃了泛型类型,转而支持Attributes 的基本类型,但我不明白为什么或在哪里。
查看the playground link 以获得问题演示。
【问题讨论】:
-
尝试从
singleAttributes中删除显式返回类型。在大多数情况下,TS 应该推断返回类型 -
这似乎可行,但我仍然很好奇为什么
T不是静态有效的返回类型?
标签: typescript json-api