我们应该在转换通用 json 响应时使用“any”吗
Posted
技术标签:
【中文标题】我们应该在转换通用 json 响应时使用“any”吗【英文标题】:Should we use "any" when transforming a generic json response 【发布时间】:2021-02-24 01:02:12 【问题描述】:我不确定在打字稿项目中为函数创建输入/输出中任何类型的函数是否好,以及如何在“严格类型检查”和“灵活性”之间取得平衡。
现在我正在尝试创建一个辅助函数来删除 graphQL 响应中的边和节点,以便在视图组件中更轻松地处理,举个例子:
// Input A
"students":
"edges": [
"node":
"name": "Peter",
"age": 12
,
"node":
"name": "Mike",
"age": 12
]
// Input B
"teachers":
"edges": [
"node":
"name": "Mary",
"age": 40
,
"node":
"name": "John",
"age": 35
]
我建议的辅助函数:
const simpleConnectionsHandler = (obj: any): any =>
// Some logic to remove edges and nodes
...
期待我能从函数中得到什么(输出):
// Output A
"students": [
"name": "Peter", "age": 12 ,
"name": "Mike", "age": 12
]
// Output B
"teachers": [
"name": "Mary", "age": 40 ,
"name": "John", "age": 35
]
在我的视图组件中,我将采用这样的简化版响应:
const studentList: studentsSimplified = simpleConnectionsHandler(inputA);
const teacherList: teachersSimplified = simpleConnectionsHandler(inputB);
我这样做的原因是,我想防止为响应json声明两种版本的类型,一种是带有边和节点的响应,一种是没有边和节点的响应。
我想知道接受输入为“any”并返回“any”作为输出是否好,当我在调用方返回结果时,我转换回响应的简化版本。
【问题讨论】:
听起来像是一个设计决定。对我来说,“simpleConnectionsHandler”似乎表明它正在发出请求。但是,实际功能似乎是从图形结构中解开对象。首先要做的是了解您要分离和封装的责任。如果它是一个概念上一致的操作,恰好有多个返回类型,那么你可以使用一个通用的typescriptlang.org/docs/handbook/generics.html 感谢@farlee2121,在示例中它假设函数的输入/输出属于同一类型。在我的情况下,输入和输出应该是两种不同的类型,如何在不使用any
的情况下解决它
这更像是一个typescript
的问题,而不是reactjs
。如果标记正确,打字稿人更有可能回答
【参考方案1】:
这就是泛型的用途。
const simpleConnectionsHandler = <T>(obj: any): T =>
// Some logic to remove edges and nodes
...
const studentList: studentsSimplified = simpleConnectionsHandler<studentsSimplified>(responseA);
const teacherList: teachersSimplified = simpleConnectionsHandler<teachersSimplified>(responseB);
注意:您可以像这样隐含变量类型:
const studentList = simpleConnectionsHandler<studentsSimplified>(responseA);
const teacherList = simpleConnectionsHandler<teachersSimplified>(responseB);
【讨论】:
谢谢@jc-ford 让我试一试。但我想知道我们是否应该防止在打字稿项目中使用“任何”?明白我们可以在这里使用泛型,但是 obj 中的“any”,这是一个好习惯吗? 我会说这取决于。在某些情况下,您真的无法知道对象的类型,而any
是唯一的选择。没有“从不使用任何”规则。这是一个判断电话。
在某些情况下,例如,对象的类型并不重要。例如,一个日志函数可能需要一个 any
参数,它只是要序列化和存储。【参考方案2】:
这似乎不是泛型的工作,因为您的所有类型都已明确定义。
我建议自己定义节点类型,然后将图形格式描述如下:
type MyNode = name: string, age: number ;
type graph =
[x: string]:
edges: Array<
node: MyNode
>
;
function name(params: graph): [x: string]: MyNode[]
return ...
用您拥有的任何已知密钥替换通用 [x: string]
。
正如您在此代码片段中看到的,我已经描述了包含所有预期字段的整个输入,因此不仅仅是任何 js 对象都可以进入。
我已经定义了一种类型 MyNode,它可以用来组成图的其余部分,以及组成返回类型。
如果你甚至想限制[x: string]
可以变成什么,你可以在这里查看:Typescript: How to use a generic parameter as object key
并实际编写一个通用函数来保证结果具有相同的键。
例如:
type knownKeys = 'teacher' | 'student';
type MyNode = name: string, age: number ;
type graph<T extends knownKeys> =
[x in T]:
edges: Array<
node: MyNode
>
;
function myFunction<T extends knownKeys>(params: graph<T>): [x in T]: MyNode[]
return
// use
const a = myFunction<'teacher'>(
teacher:
edges: [
node: name: 'hi', age: 42, ,
],
);
【讨论】:
如果MyNode
(即json中的属性)甚至是动态的怎么办? @vickson我可以传入不同种类的json,没有标准类型/结构。这个辅助函数 (simpleConnectionsHandler) 用于任何 graphQL 响应的转换目的
取决于你对 MyNode 的预测能力,你总是可以尽可能地描述它的结构。如果您不知道会发生什么,请明确说明any
是解决方案,因为您明确说明“甚至我都不知道将要扔给我什么”。
另一方面,您始终可以使用联合类型列出您将收到的所有可能格式。见typescriptlang.org/docs/handbook/unions-and-intersections.html
注意,在我的情况下,我实际上并不知道输入结构是什么,辅助函数只专注于从 json 中消除边和节点。在这种情况下,我将其保留为 any
。谢谢。 @维克森
另外,不要将“我的功能期望什么”与“用户将要喂给我什么”混为一谈。在制作打字稿功能时,请始终说明“我的功能期望什么”。你正在为人们制作一个隐含的文档,你希望他们为你提供一个特定结构的对象。用户可以随时myFunction(myObject as any)
强制调用你的函数。然后他们有责任确保myObject
至少符合您的预期参数以上是关于我们应该在转换通用 json 响应时使用“any”吗的主要内容,如果未能解决你的问题,请参考以下文章
使用 Fuel 和 Result 将字节数组转换为 Json