定义数组,元素可能是字符串或数值
大约 3 分钟
定义包含字符串或数值类型的数组
在 TypeScript 中,有多种方式可以定义一个元素可能是字符串类型也可能是数值类型的数组。以下是几种常用的方法:
1. 联合类型数组(推荐)
使用联合类型 string | number 来定义数组:
// 方法1:使用类型注解
let mixedArray: (string | number)[] = ["hello", 42, "world", 100];
// 方法2:使用 Array<联合类型> 语法
let mixedArray2: Array<string | number> = [1, "two", 3, "four"];
// 方法3:类型推断(如果初始化时提供值)
let mixedArray3 = ["hello", 42, "world", 100]; // 推断为 (string | number)[]2. 实际使用示例
// 存储用户ID和用户名的混合数组
let userIdsAndNames: (string | number)[] = [
1001,
"Alice",
1002,
"Bob",
1003,
"Charlie"
];
// 处理混合类型数组
function processMixedArray(arr: (string | number)[]): void {
arr.forEach(item => {
if (typeof item === "string") {
console.log(`String: ${item.toUpperCase()}`);
} else {
console.log(`Number: ${item.toFixed(2)}`);
}
});
}
processMixedArray(["hello", 42, "world", 3.14159]);3. 使用类型别名
为了提高代码可读性和复用性,可以定义类型别名:
// 定义类型别名
type StringOrNumber = string | number;
// 使用类型别名定义数组
let mixedArray: StringOrNumber[] = ["hello", 123, "world", 456];
// 或者更复杂的类型别名
type MixedData = (string | number | boolean)[];
let complexArray: MixedData = ["yes", 42, true, "no", 0, false];4. 使用接口定义
interface MixedArray extends Array<string | number> {}
let data: MixedArray = [1, "two", 3, "four"];5. 泛型约束方式
// 定义泛型类型
type FlexibleArray<T extends (string | number)> = T[];
let stringArray: FlexibleArray<string> = ["a", "b", "c"];
let numberArray: FlexibleArray<number> = [1, 2, 3];
let mixedArray: FlexibleArray<string | number> = ["hello", 42, "world"];6. 处理数组元素的类型守卫
当操作这种混合类型数组时,通常需要使用类型守卫来区分不同类型的元素:
function isString(value: string | number): value is string {
return typeof value === "string";
}
function isNumber(value: string | number): value is number {
return typeof value === "number";
}
function processMixedData(data: (string | number)[]): void {
data.forEach(item => {
if (isString(item)) {
// 在这个代码块中,TypeScript 知道 item 是 string 类型
console.log(`Processing string: ${item.charAt(0)}`);
} else if (isNumber(item)) {
// 在这个代码块中,TypeScript 知道 item 是 number 类型
console.log(`Processing number: ${item.toFixed(2)}`);
}
});
}
// 使用示例
const mixedData: (string | number)[] = ["hello", 123, "typescript", 456.789];
processMixedData(mixedData);7. 更复杂的联合类型数组
// 包含多种基本类型的数组
let veryMixedArray: (string | number | boolean | null)[] = [
"text",
42,
true,
null,
"more text",
3.14
];
// 包含对象和基本类型的数组
type MixedContent = string | number | { id: number; name: string };
let contentArray: MixedContent[] = [
"hello",
42,
{ id: 1, name: "object" },
"world"
];8. 数组方法的使用
let mixedArray: (string | number)[] = ["hello", 42, "world", 100];
// 使用数组方法
const strings = mixedArray.filter((item): item is string => typeof item === "string");
const numbers = mixedArray.filter((item): item is number => typeof item === "number");
console.log(strings); // ["hello", "world"]
console.log(numbers); // [42, 100]
// 映射操作
const processed = mixedArray.map(item => {
if (typeof item === "string") {
return item.toUpperCase();
} else {
return item * 2;
}
});
console.log(processed); // ["HELLO", 84, "WORLD", 200]9. 使用 any 类型(不推荐)
// 虽然可以工作,但不推荐,因为失去了类型安全性
let mixedArray: any[] = ["hello", 42, "world", 100];最佳实践建议
- 优先使用联合类型:
(string | number)[]是最清晰和类型安全的方式 - 使用类型别名:对于复杂的联合类型,定义类型别名提高可读性
- 使用类型守卫:在处理数组元素时使用类型守卫来区分不同类型
- 避免使用
any:除非确实需要完全动态的类型 - 考虑数据结构:如果数组中字符串和数字有特定的模式,考虑使用更明确的数据结构
// 推荐的实践示例
type IdOrName = string | number;
class DataManager {
private data: IdOrName[] = [];
add(item: IdOrName): void {
this.data.push(item);
}
getStrings(): string[] {
return this.data.filter((item): item is string => typeof item === "string");
}
getNumbers(): number[] {
return this.data.filter((item): item is number => typeof item === "number");
}
processAll(): void {
this.data.forEach(item => {
if (typeof item === "string") {
console.log(`String item: ${item}`);
} else {
console.log(`Number item: ${item}`);
}
});
}
}这种方式既保持了类型安全性,又提供了足够的灵活性来处理混合类型的数组数据。