ZetCode

TypeScript 的 Any 类型

最后修改于 2025 年 3 月 5 日

TypeScript 中的 any 类型是一个强大但潜在有风险的工具,它会禁用变量或表达式的类型检查。在处理动态或未类型化数据时,它提供了灵活性,但牺牲了 TypeScript 通常提供的类型安全。本教程将通过实际示例探讨 any 类型,以说明其用法和影响。

TypeScript 旨在强制执行静态类型,在编译时捕获错误。然而,any 类型会退出此系统,将值视为可以具有任何类型。在与 JavaScript 集成、处理第三方库或处理未知结构的数据时,它通常用作后备方案。虽然方便,但过度使用会削弱 TypeScript 的优势,使代码更难维护和调试。

Any 的基本用法

any 类型允许变量在没有类型限制的情况下持有任何值。此示例演示了其基本灵活性。

basic_any.ts
let value: any = 42;
value = "Hello";
value = true;

console.log(value); // Output: true

变量 valueany 类型声明,允许它被赋值为一个数字 (42),然后是一个字符串 ("Hello"),最后是一个布尔值 (true)。TypeScript 在此处不强制类型一致性。

输出 true 反映了最后一次赋值。这种灵活性在初始类型未知时很有用,例如动态用户输入,但它绕过了类型安全,可能在运行时隐藏错误。

带有函数的 Any

当类型不可预测时,函数可以使用 any 作为参数或返回类型。此示例处理未知输入。

any_function.ts
function processInput(input: any): any {
    return input;
}

console.log(processInput(5));      // Output: 5
console.log(processInput("test")); // Output: test

processInput 函数接受一个 any 类型参数并返回 any。它可以处理数字、字符串或任何其他类型而不会出现类型错误。

输出是 5 和 "test",分别对应输入。虽然这适用于不可预测的数据,但它失去了类型安全——如果在 input 是数字的情况下在内部调用 input.toUpperCase(),它仍然会编译,但有运行时错误的风险。

带对象的 Any

类型为 any 的对象允许无限制地访问属性。此示例操作了一个未类型化的对象。

any_object.ts
let data: any = { name: "Alice" };
data.age = 30;
data.active = true;

console.log(data); // Output: { name: "Alice", age: 30, active: true }

data 变量,类型为 any,开始时是一个带有 name 属性的对象。然后,它在没有类型检查的情况下接受新属性(ageactive)。

输出显示了修改后的对象。这对于动态数据(如来自 API 的 JSON)很有用,但访问 data.foo(不存在)会编译,尽管存在潜在的运行时问题,从而降低了安全性。

带数组的 Any

类型为 any 的数组可以包含混合类型。此示例构建了一个异构数组。

any_array.ts
let mixed: any[] = [1, "two"];
mixed.push(true);
mixed.push({ key: "value" });

console.log(mixed); // Output: [1, "two", true, { key: "value" }]

mixed 数组,类型为 any[],开始时是一个数字和一个字符串。然后,它通过 push 接受一个布尔值和一个对象,所有这些都没有类型错误。

输出反映了这种混合:[1, "two", true, { key: "value" }]。这适用于数组内容不可预测的情况,但像 mixed[0].toUpperCase() 这样的操作即使无效也会编译,有出错的风险。

隐式 Any

当未指定类型时,TypeScript 会推断 any,除非启用了 noImplicitAny。此示例显示了隐式 any

implicit_any.ts
// With `noImplicitAny: false` in tsconfig.json
function logValue(value) {
    console.log(value);
}

logValue(42);      // Output: 42
logValue("Hello"); // Output: Hello

如果没有类型注解,logValue 中的 valuenoImplicitAny 关闭时为隐式 any。它接受任何输入—42 和 "Hello"—并记录它们,而无需编译时检查。

输出是 42 和 "Hello"。如果 noImplicitAny: true,TypeScript 会报错,需要显式类型。隐式 any 模仿了 JavaScript 的灵活性,但会削弱类型安全。

带类型断言的 Any

any 类型值的类型已知时,类型断言可以对其进行细化。此示例从 any 断言了一个类型。

any_assertion.ts
let rawData: any = "Hello World";
const str: string = rawData as string;

console.log(str.toUpperCase()); // Output: HELLO WORLD

rawData 变量是 any 类型,包含一个字符串。as string 断言告诉 TypeScript 将其视为 string,从而启用了 toUpperCase()

输出 "HELLO WORLD" 证实了该操作。没有断言,rawData.toUpperCase() 会编译,但不是类型安全的。断言将 any 连接到类型化代码,但需要开发者的确定性。

第三方库中的 Any

在为未类型化的库输出添加类型时,any 类型很常见。此示例模拟了一个未类型化的 API 响应。

any_library.ts
// Simulating an untyped library function
declare function fetchData(): any;

const response = fetchData();
response.name = "Test";
console.log(response.name); // Output: Test (assumed)

fetchData 函数被声明为返回 any,模拟了一个未类型化的库。response 变量接受任何修改,例如添加 name 属性。

输出 "Test" 假定赋值在运行时有效。这对于未类型化的 JavaScript 库很实用,但如果假设(例如 response.name 存在)失败,则有运行时错误的风险。

带动态数据的 Any

动态数据(如 JSON)通常首先使用 any。此示例使用 any 解析 JSON。

any_json.ts
const jsonString = '{"id": 1, "title": "Book"}';
const parsed: any = JSON.parse(jsonString);

console.log(parsed.title); // Output: Book

parsed 变量,类型为 any,保存了 JSON.parse 的结果,TypeScript 无法在没有上下文的情况下精确地对其进行类型化。它允许直接访问 title

输出 "Book" 与 JSON 数据匹配。但是,parsed.foo 会在运行时未定义的情况下编译。这对于动态数据的快速原型设计很有用,但需要进行调整以提高安全性。

最佳实践

来源

TypeScript Any 类型文档

本教程通过实际示例介绍了 TypeScript 的 any 类型。请明智地使用它,以在代码中平衡灵活性和类型安全。

作者

我叫 Jan Bodnar,是一名充满热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。至今,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 TypeScript 教程