TypeScript中的JSON:5个致命的类型转换错误及修复方法

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:关于“魔法”类型转换的迷思

\n\n

每个TypeScript开发者迟早都会遇到这样的情况:您从服务器获取JSON数据,确信自己了解其结构,然后通过as进行简单的类型转换。然后……一切都不工作了。类方法缺失,字段为undefined,调试变成了一场解谜游戏。

\n\n

“如何将JSON对象转换为TypeScript类?”这个问题是Stack Overflow上最热门的问题之一(浏览量达数万次)。这并不奇怪。TypeScript是一个仅在编译期存在的超集。在运行时,您的“类”实际上只是一个普通JavaScript对象。

\n\n

在本文中,我们将分析开发者在处理JSON和TypeScript类时最常犯的5个危险错误。您将了解如何避免这些错误,并获得适用于生产环境的现成解决方案。

\n\n

错误#1:使用as进行“真正”的类型转换

\n\n

最常见的陷阱是认为jsonData as MyClass这种结构会创建一个类的实例。

\n\n

实际情况是什么?

\n

as运算符(或尖括号语法)是一种类型断言。它告诉编译器:“相信我,我知道这个类型。”但在JavaScript中,它不会执行任何魔法操作。

\n\n
class User {\n    name: string = '';\n    greet(): string {\n        return `你好,${this.name}!`;\n    }\n}\n\nconst rawData = JSON.parse('{"name": "安娜"}');\nconst user = rawData as User;\n\nconsole.log(user.name); // "安娜" — 正常工作\nconsole.log(user.greet()); // TypeError: user.greet is not a function\n
\n\n

为什么?因为rawData只是一个普通对象{ name: '安娜' }。它没有User.prototype原型,因此也没有greet方法。

\n\n

如何修复?

\n

始终创建真正的类实例。基本方法是使用Object.assign:

\n\n
const user = Object.assign(new User(), rawData);\nconsole.log(user.greet()); // "你好,安娜!"\n
\n\n

但这种方法有一些细节问题,我们将在后面讨论。

\n\n

错误#2:忽略嵌套对象和数组

\n\n

您高兴地使用Object.assign,但您的数据包含嵌套结构。然后麻烦就开始了。

\n\n
class Address {\n    city: string = '';\n    zip: string = '';\n}\n\nclass Company {\n    name: string = '';\n    address: Address = new Address();\n}\n\nconst data = JSON.parse('{"name": "TechCorp", "address": {"city": "莫斯科", "zip": "101000"}}');\nconst company = Object.assign(new Company(), data);\n\nconsole.log(company.address.city); // "莫斯科" — 运气好?\nconsole.log(company.address instanceof Address); // false!\n
\n\n

问题:address仍然是一个普通对象,而不是Address的实例。如果Address有方法或计算属性,它们将会丢失。

\n\n

解决方案:递归类型转换

\n

编写工厂函数或使用class-transformer库:

\n\n
import { plainToClass } from 'class-transformer';\n\nconst company = plainToClass(Company, data);\nconsole.log(company.address instanceof Address); // true\n
\n\n

class-transformer会递归遍历所有字段,并根据@Type装饰器创建正确的类实例。

\n\n

错误#3:丢失默认值

\n\n

TypeScript允许直接在类中设置字段的默认值。但在JSON“类型转换”时,这些值可能会被undefined覆盖。

\n\n
class Config {\n    theme: string = 'light';\n    fontSize: number = 14;\n    language: string = 'ru';\n}\n\nconst partialData = JSON.parse('{"theme": "dark"}');\nconst config = Object.assign(new Config(), partialData);\n\nconsole.l                

博客

书籍推荐