文章目录

TypeScript 联合类型:string | number 的使用

发布于 2026-04-08 16:28:55 · 浏览 4 次 · 评论 0 条

TypeScript 联合类型:string | number 的使用

基本概念理解

了解 TypeScript 联合类型的基本概念。联合类型是一种允许变量具有多种类型之一的特性,使用 | 操作符连接不同类型。string | number 表示一个值可以是字符串或数字类型。

声明 一个 string | number 类型的变量:

let value: string | number;
value = "Hello"; // 有效
value = 42; // 有效
value = true; // 错误,不能赋值为布尔值

类型收窄技术

使用 typeof 操作符收窄联合类型。typeof 是 TypeScript 内置的类型保护机制,可以帮助在运行时确定值的实际类型。

编写 类型收窄函数:

function processValue(value: string | number): string {
    if (typeof value === 'string') {
        // 在这个块中,TypeScript 知道 value 是字符串类型
        return value.toUpperCase();
    } else {
        // 在这个块中,TypeScript 知道 value 是数字类型
        return value.toString();
    }
}

注意 类型收窄只在条件判断中有效,确保每个条件分支都处理了所有可能的类型。

实用场景与示例

表单数据处理

处理 用户表单提交的数据,其中某些字段可能是字符串也可能是数字:

type FormData = {
    username: string;
    age: string | number;
    email: string;
};

function validateAge(age: string | number): boolean {
    if (typeof age === 'string') {
        const parsedAge = parseInt(age, 10);
        return !isNaN(parsedAge) && parsedAge > 0;
    } else {
        return age > 0;
    }
}

function submitForm(data: FormData) {
    if (validateAge(data.age)) {
        // 提交表单
        console.log("表单提交成功");
    } else {
        console.log("年龄无效");
    }
}

// 使用示例
submitForm({
    username: "john_doe",
    age: "25", // 可以是字符串
    email: "john@example.com"
});

submitForm({
    username: "jane_doe",
    age: 30, // 可以是数字
    email: "jane@example.com"
});

API 响应处理

处理 从 API 获取的数据,某些字段可能是字符串或数字:

interface ApiResponse {
    id: string | number;
    name: string;
    score: string | number;
}

function processApiResponse(response: ApiResponse): string {
    const id = typeof response.id === 'number' ? `#${response.id}` : response.id;
    const score = typeof response.score === 'number' 
        ? `分数: ${response.score}` 
        : `分数: ${parseInt(response.score, 10)}`;
    
    return `${id} - ${response.name} - ${score}`;
}

// 使用示例
const response1: ApiResponse = {
    id: 123,
    name: "Alice",
    score: 95
};

const response2: ApiResponse = {
    id: "ABC-456",
    name: "Bob",
    score: "88"
};

console.log(processApiResponse(response1)); // #123 - Alice - 分数: 95
console.log(processApiResponse(response2)); // ABC-456 - Bob - 分数: 88

数组元素处理

操作 包含字符串和数字的数组:

function sumOrConcatenate(values: (string | number)[]): string | number {
    if (values.every(val => typeof val === 'number')) {
        // 所有元素都是数字,进行求和
        return (values as number[]).reduce((sum, val) => sum + val, 0);
    } else if (values.every(val => typeof val === 'string')) {
        // 所有元素都是字符串,进行连接
        return (values as string[]).join('');
    } else {
        // 混合类型,返回连接后的字符串
        return values.map(val => val.toString()).join('-');
    }
}

// 使用示例
console.log(sumOrConcatenate([1, 2, 3])); // 6 (数字)
console.log(sumOrConcatenate(["a", "b", "c"])); // "abc" (字符串)
console.log(sumOrConcatenate([1, "2", 3])); // "1-2-3" (字符串)

类型断言与类型守卫

使用 类型断言(Type Assertion)当确定值的类型时:

function formatValue(value: string | number): string {
    // 使用类型断言告诉 TypeScript value 是字符串
    return (value as string).toUpperCase();
}

创建 自定义类型守卫函数:

function isString(value: string | number): value is string {
    return typeof value === 'string';
}

function process(value: string | number) {
    if (isString(value)) {
        console.log(value.length); // 只有在这里才能安全访问 .length
    } else {
        console.log(value * 2); // 只有在这里才能进行数学运算
    }
}

常见错误与解决方案

错误:尝试在联合类型上调用特定方法

// 错误示例
function processValue(value: string | number) {
    // 错误:数字类型没有 toUpperCase 方法
    return value.toUpperCase(); 
}

解决 使用类型收窄或类型保护:

// 解决方案
function processValue(value: string | number) {
    if (typeof value === 'string') {
        return value.toUpperCase();
    } else {
        return value.toString();
    }
}

错误:使用类型比较而非值比较

// 错误示例
function checkType(a: string | number, b: string | number) {
    // 错误:比较的是类型而非值
    return typeof a === typeof b;
}

解决 比较实际的值而非类型:

// 解决方案
function checkType(a: string | number, b: string | number) {
    // 正确:比较实际值
    return a === b;
}

最佳实践

  1. 优先使用类型收窄 而不是类型断言,类型收窄更安全。

  2. 创建类型守卫函数 当需要多次检查同一类型时。

  3. 为联合类型创建别名 提高代码可读性:

type ID = string | number;

function processId(id: ID): string {
    if (typeof id === 'string') {
        return `ID-${id}`;
    }
    return `ID-${id.toString()}`;
}
  1. 使用联合类型接口 为复杂对象定义联合类型:
type User = {
    name: string;
    id: string | number;
    age: number;
};

type Admin = {
    name: string;
    id: string | number;
    level: number;
};

type UserOrAdmin = User | Admin;

function processUser(user: UserOrAdmin) {
    console.log(user.name);
    if ('age' in user) {
        console.log(`用户年龄: ${user.age}`);
    } else {
        console.log(`管理员级别: ${user.level}`);
    }
}
  1. 避免过度使用联合类型 如果可能,考虑使用更精确的类型系统如枚举或联合类型与字面量类型的组合:
// 更好的方式
type AgeUnit = 'years' | 'months' | 'days';
type Age = {
    value: number;
    unit: AgeUnit;
};

应用 联合类型可以大大提高代码的灵活性,特别是在处理不确定数据类型或API响应时。记住 始终考虑类型的边界情况,并确保所有可能的类型都被适当处理。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文