我们应该在转换通用 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”吗的主要内容,如果未能解决你的问题,请参考以下文章

swift3 模型转字典(JSON)

swift3 模型转字典(JSON)

如何将对象响应对象的猫鼬聚合数组转换为json对象响应

使用 Fuel 和 Result 将字节数组转换为 Json

JSON "Any" 不能转换为 'NSDictionary' 以及如何确定转换类型

当 XML SOAP 响应中存在单个元素时,JSON 对象而不是数组