类型安全问题会影响系统的稳定性。举个例子:
- 把字符串当成数字进行数学运算,得到错误结果。
- 用户输入错误数据,导致系统异常。
以下是常见的类型报错:
text
- TypeError: Cannot read property "xx" of undefined
- TypeError: Cannot set properties of undefined
- TypeError: 'undefined' is not a function
一. 静态类型安全
一个经典的类型错误:
javascript
function add(a, b){
return a + b;
}
add(1, 1); // 预期值 2
add('1', 1); // 错误值 '11'
上面代码在编译时和运行时都不会报错,但是有可能得到错误的结果。
这类问题是代码本身引入的,在调用函数时传入了错误的数据类型。
解决方案是使用TypeScript。TypeScript是类型安全的语言,会在编译时检查变量类型。
javascript
function add(a:number, b:number){
return a + b;
}
add(1, 1); // 编译通过
add('1', 1); // 编译报错,类型检查不通过
二. 动态类型安全
除了代码本身引入的类型错误,外界输入也是存在风险的。例如,用户输入 或接口参数 等变量,在编译阶段是不知道变量值的,只能在运行时校验。所以我们需要有一个强大的运行时数据类型校验工具,例如zod。
- 基本数据类型检验
在zod中,每一种数据类型都有对应的schema实现。
javascript
import { z } from "zod";
// 创建一个字符串schema
const stringSchema = z.string();
// 数据校验
stringSchema.parse("abc"); // => "abc"
stringSchema.parse(123); // => throws ZodError
// 数据校验(不会抛异常)
stringSchema.safeParse("abc"); // => { success: true; data: "abc" }
stringSchema.safeParse(123); // => { success: false; error: ZodError }
// 常见的schema如下:
z.string();
z.number();
z.bigint();
z.boolean();
z.date();
z.symbol();
对于复杂的数据类型,例如对象,则可以通过多个schema组合的方式实现。
- 复杂数据类型检验
javascript
import { z } from "zod";
// 创建一个对象schema
const userSchema = z.object({ username: z.string(), age: z.number()});
// 数据校验
userSchema.parse({ username: "Ludwig", age: 10 });
- 实践案例
下面以一个用户信息表单为例。
首先,设计出用户信息如下:
json
{
"姓名": 最长32位字符串,必填
"年龄": 正整数,必填
"邮箱": 邮箱地址,必填
"头像": 图片链接,可选
}
然后,定义表单schema:
javascript
export const userSchema = z.object({
name: z.string().max(32),
age: z.number({required_error: '请输入年龄'})
.int({message:'年龄是一个正整数'})
.positive({message:'年龄是一个正整数'}),
email: z.string().email(),
image: z.string().url(),
})
最后,在提交表单时校验数据。
javascript
// extract the inferred type
// { name: string, age: number, email: string, image: string}
type UserType = z.infer<typeof userSchema>;
function submit(UserType formData){
const data = userSchema.parse(formData);
// ...
}
总结
对于Web应用来说,类型安全问题无处不在。例如,代码本身引入的类型错误;用户输入的数据类型不对;或者接口传参的类型错误等等。这些都会影响系统的稳定性。
所以,我们要构建类型安全的应用,包括以下两点:
- 第一,静态类型安全。使用TypeScript等类型安全的语言,在编译阶段检查类型。
- 第二,动态类型安全。使用zod等检验工具,在运行时检验数据。