TypeScript中的any


版权声明


TypeScript中的any概述

any 是 TypeScript 中比较特殊的一种类型。它表示任意类型,也就是说,一个被标注为 any 的值可以保存字符串、数字、布尔值、对象、数组等各种数据。表面上看,any 非常灵活,因为它几乎不会限制变量的赋值和使用。但正因为限制很少,它也会削弱 TypeScript 原本提供的类型检查能力。

普通类型会对变量形成明确约束。例如,string 类型的变量只能保存字符串,number 类型的变量只能保存数字,boolean 类型的变量只能保存布尔值。而 any 不同,它表示这个值可以是任意类型。一个变量如果被标注为 any,后续既可以赋值为字符串,也可以赋值为数字、布尔值、对象或数组。这样虽然方便,但也意味着 TypeScript 很难继续判断这个变量的真实结构和可用方法。

any 最大的问题是会让类型检查变弱。正常情况下,如果一个变量是字符串,TypeScript 可以提示字符串相关方法;如果一个变量是数字,TypeScript 会阻止我们调用字符串方法。但是当变量是 any 时,TypeScript 往往不会严格检查它的方法是否真实存在。即使代码中调用了一个不存在的方法,也可能无法在编写阶段及时发现,最终把问题留到运行时才暴露。

any 也会影响编辑器的代码提示。TypeScript 的重要作用之一,是让编辑器根据变量类型提供更准确的属性和方法提示。如果变量类型明确,编辑器可以根据 stringnumber、对象类型、接口等信息给出对应提示;如果变量是 any,编辑器就很难准确判断它到底有哪些属性和方法。过多使用 any,会让 TypeScript 带来的提示和检查效果明显下降。

在数组、对象和函数参数中使用 any 时,也要特别谨慎。any[] 表示数组中可以保存任意类型的数据,如果一个数组本来只用于保存用户名,就不应该写成 any[]。对象如果被标注为 any,TypeScript 很难检查属性是否存在、属性名是否写错、属性值类型是否正确。函数参数如果使用 any,调用函数时就容易传入不合适的数据,函数内部调用某种类型特有的方法时也可能出现运行时错误。

any 和联合类型容易被初学者混淆。二者都能让一个值看起来更灵活,但含义并不相同。any 表示任意类型,限制非常少;联合类型表示只能在几个明确类型中选择。例如,string | number 只允许字符串或数字,不允许布尔值、对象或数组。如果一个数据只允许几种明确类型,应该优先使用联合类型,而不是使用 any

any 并不是完全不能使用。在少数过渡场景中,它可以临时出现。例如,接口返回结构暂时不明确、旧 JavaScript 项目逐步迁移到 TypeScript、第三方数据暂时没有类型定义时,可以临时使用 any。但是这些情况都应该视为过渡方案。等数据结构明确后,应尽量改成具体类型、对象类型、类型别名、接口或联合类型。

减少 any 的基本思路是:能写清楚类型时,就不要使用 any。字符串使用 string,数字使用 number,布尔值使用 boolean;对象结构明确时,使用对象类型、类型别名或接口;值只允许几种类型时,使用联合类型;如果只是暂时不知道类型,也可以考虑使用更严格的 unknown。这样既能保持 TypeScript 的灵活性,也能保留类型检查和代码提示带来的优势。

对于准备学习 Vue3 的初学者来说,理解 any 的重点不在于大量使用它,而在于知道它为什么危险。后续阅读 Vue3 项目代码时,如果看到 any,要意识到这里的类型检查可能比较弱;如果自己编写代码,也不要为了省事把不确定的数据都写成 any。只有在暂时无法确定类型时,才把它作为临时选择。

案例源码

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>TypeScript 中的 any</title>
</head>
<body>
  <h1>TypeScript 中的 any</h1>

  <p>
    本节学习 TypeScript 中的 <code>any</code> 类型。
    <code>any</code> 表示任意类型,也就是一个值可以是字符串、数字、布尔值、对象、数组等任何类型。
  </p>

  <p>
    对初学者来说,<code>any</code> 看起来很方便,因为它几乎不会限制变量的使用。
    但是,过度使用 <code>any</code> 会让 TypeScript 的类型检查能力变弱。
    因此,本节不仅要学习 <code>any</code> 的写法,还要理解为什么不建议随意使用它。
  </p>

  <p>
    说明:本节中的代码是 TypeScript 代码,浏览器不能直接运行。
    当前阶段建议使用 TypeScript 官方在线工具
    <a href="https://www.typescriptlang.org/play/" target="_blank">TypeScript Playground</a>
    测试代码。
  </p>

  <hr>

  <h2>一、什么是 any 类型</h2>

  <p>
    <code>any</code> 表示任意类型。
    如果一个变量被标注为 <code>any</code>,它就可以保存任何类型的数据。
  </p>

  <pre><code>let value: any = "hello";

value = 100;
value = true;
value = { username: "jack" };
value = [1, 2, 3];</code></pre>

  <p>
    上面代码中,<code>value</code> 一开始保存字符串,
    后面又被赋值为数字、布尔值、对象和数组。
    因为它的类型是 <code>any</code>,所以 TypeScript 不会提示这些赋值错误。
  </p>

  <p>
    可以这样理解:
  </p>

  <pre><code>let value: any;</code></pre>

  <p>
    表示:
    <code>value</code> 可以是任何类型。
  </p>

  <p>
    这就是 <code>any</code> 的基本含义:
    <strong>放弃对这个值的具体类型检查。</strong>
  </p>

  <hr>

  <h2>二、any 的基本写法</h2>

  <p>
    <code>any</code> 可以像普通类型一样写在变量后面。
  </p>

  <pre><code>let 变量名: any = 值;</code></pre>

  <p>
    例如:
  </p>

  <pre><code>let data: any = "TypeScript";

data = 100;
data = false;</code></pre>

  <p>
    这段代码中:
  </p>

  <ol>
    <li><code>data</code> 是变量名。</li>
    <li><code>: any</code> 表示 <code>data</code> 可以保存任意类型的值。</li>
    <li>后续给 <code>data</code> 赋值字符串、数字或布尔值,TypeScript 都不会报错。</li>
  </ol>

  <p>
    <code>any</code> 也可以用于函数参数。
  </p>

  <pre><code>function printValue(value: any): void {
  console.log(value);
}

printValue("hello");
printValue(100);
printValue(true);</code></pre>

  <p>
    这里的 <code>value: any</code> 表示:
    调用 <code>printValue</code> 时,可以传入任何类型的数据。
  </p>

  <hr>

  <h2>三、any 会让类型检查变弱</h2>

  <p>
    <code>any</code> 最大的问题是:
    它会让 TypeScript 不再严格检查这个值的类型。
  </p>

  <pre><code>let value: any = "hello";

console.log(value.length);
console.log(value.toUpperCase());</code></pre>

  <p>
    上面代码中,<code>value</code> 实际保存的是字符串,
    所以访问 <code>length</code> 和调用 <code>toUpperCase()</code> 都可以理解。
  </p>

  <p>
    但是,如果后面把 <code>value</code> 改成数字,TypeScript 仍然不会提前提示问题。
  </p>

  <pre><code>let value: any = 100;

console.log(value.toUpperCase());</code></pre>

  <p>
    这段代码在 TypeScript 编写阶段可能不会报错,
    但是运行时会出问题。
    因为数字没有 <code>toUpperCase()</code> 方法。
  </p>

  <p>
    这说明:
    <strong>使用 any 后,TypeScript 很难帮助我们提前发现类型错误。</strong>
  </p>

  <hr>

  <h2>四、any 和普通类型的区别</h2>

  <p>
    普通类型会限制变量只能保存对应类型的数据。
  </p>

  <pre><code>let username: string = "jack";

username = "lucy"; // 正确
username = 100;    // 错误</code></pre>

  <p>
    上面代码中,<code>username</code> 是字符串类型,
    所以不能赋值为数字。
  </p>

  <p>
    但是,如果使用 <code>any</code>,TypeScript 就不会继续限制它。
  </p>

  <pre><code>let username: any = "jack";

username = "lucy";
username = 100;
username = true;</code></pre>

  <p>
    这段代码中,<code>username</code> 可以被赋值为多种类型。
  </p>

  <p>
    二者区别可以概括为:
  </p>

  <ol>
    <li><code>string</code>:只能保存字符串。</li>
    <li><code>number</code>:只能保存数字。</li>
    <li><code>boolean</code>:只能保存布尔值。</li>
    <li><code>any</code>:可以保存任意类型。</li>
  </ol>

  <p>
    <code>any</code> 的灵活性更强,但类型安全性更弱。
  </p>

  <hr>

  <h2>五、any 会影响后续代码提示</h2>

  <p>
    TypeScript 的一个重要作用是帮助编辑器提供代码提示。
    但是,如果变量是 <code>any</code> 类型,编辑器就很难准确知道它有哪些属性和方法。
  </p>

  <pre><code>let username: string = "jack";

console.log(username.toUpperCase());</code></pre>

  <p>
    上面代码中,<code>username</code> 是字符串。
    编辑器可以提示字符串相关的方法,例如 <code>toUpperCase()</code>、
    <code>toLowerCase()</code>、<code>includes()</code> 等。
  </p>

  <p>
    如果变量是 <code>any</code>,情况就不同了。
  </p>

  <pre><code>let username: any = "jack";

console.log(username.toUpperCase());
console.log(username.notExistMethod());</code></pre>

  <p>
    因为 <code>username</code> 是 <code>any</code>,
    TypeScript 不再严格检查它的方法是否真实存在。
    即使调用了一个不存在的方法,也可能无法在编写阶段及时发现。
  </p>

  <p>
    因此,过多使用 <code>any</code> 会降低 TypeScript 带来的代码提示和错误检查效果。
  </p>

  <hr>

  <h2>六、什么时候会出现 any</h2>

  <p>
    有些时候,代码中可能会出现 <code>any</code>。
    初学阶段常见情况有以下几种。
  </p>

  <h3>情况一:手动写了 any</h3>

  <pre><code>let value: any = "hello";</code></pre>

  <p>
    这是最直接的情况。
    我们主动告诉 TypeScript:<code>value</code> 可以是任意类型。
  </p>

  <h3>情况二:变量没有明确类型</h3>

  <pre><code>let value;

value = "hello";
value = 100;</code></pre>

  <p>
    如果变量声明时没有初始值,也没有类型标注,
    TypeScript 可能很难判断它的具体类型。
    这种写法会让类型检查变弱。
  </p>

  <p>
    更推荐的写法是根据实际情况补充类型标注。
  </p>

  <pre><code>let value: string;

value = "hello";
// value = 100; // 错误:value 应该是 string</code></pre>

  <h3>情况三:第三方代码或旧代码中存在 any</h3>

  <p>
    在实际项目中,有些旧代码、第三方库或临时数据处理代码中,
    可能会看到 <code>any</code>。
    看到 <code>any</code> 时,不要直接认为代码一定错误,
    但要知道它会降低类型检查的严格程度。
  </p>

  <hr>

  <h2>七、any 可以用于数组</h2>

  <p>
    <code>any</code> 也可以用于数组。
    如果数组被标注为 <code>any[]</code>,表示数组中的元素可以是任意类型。
  </p>

  <pre><code>let list: any[] = ["jack", 18, true, { city: "北京" }];

list.push("lucy");
list.push(100);
list.push(false);</code></pre>

  <p>
    这段代码中,<code>list</code> 可以保存字符串、数字、布尔值和对象。
  </p>

  <p>
    但是,这种数组的类型约束很弱。
    如果一个数组原本只想保存用户名,就不应该使用 <code>any[]</code>。
  </p>

  <pre><code>let usernames: string[] = ["jack", "lucy", "tom"];

usernames.push("rose"); // 正确
usernames.push(100);    // 错误</code></pre>

  <p>
    和 <code>any[]</code> 相比,<code>string[]</code> 可以更好地限制数组元素类型。
  </p>

  <hr>

  <h2>八、any 可以用于对象</h2>

  <p>
    如果一个对象被标注为 <code>any</code>,
    TypeScript 不会严格检查它的属性。
  </p>

  <pre><code>let user: any = {
  username: "jack",
  age: 18
};

console.log(user.username);
console.log(user.address);
console.log(user.notExistProperty);</code></pre>

  <p>
    上面代码中,即使访问对象中不存在的属性,
    TypeScript 也可能不会及时提示问题。
  </p>

  <p>
    如果对象结构比较明确,更推荐使用对象类型、类型别名或接口。
  </p>

  <pre><code>type User = {
  username: string;
  age: number;
};

let user: User = {
  username: "jack",
  age: 18
};

console.log(user.username);
// console.log(user.address); // 错误:User 类型中没有 address 属性</code></pre>

  <p>
    这样写以后,TypeScript 可以帮助检查属性名和属性类型是否正确。
  </p>

  <hr>

  <h2>九、any 可以用于函数参数</h2>

  <p>
    函数参数也可以使用 <code>any</code>。
  </p>

  <pre><code>function printValue(value: any): void {
  console.log(value);
}

printValue("hello");
printValue(100);
printValue(true);</code></pre>

  <p>
    这种写法表示函数可以接收任意类型的参数。
    如果函数只是简单打印内容,看起来问题不大。
  </p>

  <p>
    但是,如果函数内部要调用某种类型特有的方法,使用 <code>any</code> 就可能带来风险。
  </p>

  <pre><code>function printUpperCase(value: any): void {
  console.log(value.toUpperCase());
}

printUpperCase("hello");
printUpperCase(100);</code></pre>

  <p>
    第二次调用时传入的是数字。
    数字没有 <code>toUpperCase()</code> 方法,运行时会出错。
  </p>

  <p>
    如果这个函数本来只处理字符串,就应该把参数标注为 <code>string</code>。
  </p>

  <pre><code>function printUpperCase(value: string): void {
  console.log(value.toUpperCase());
}

printUpperCase("hello");
// printUpperCase(100); // 错误:参数应该是 string</code></pre>

  <hr>

  <h2>十、any 和联合类型的区别</h2>

  <p>
    有些初学者会把 <code>any</code> 和联合类型混在一起。
    它们都可以让一个值看起来更灵活,但含义不同。
  </p>

  <p>
    <code>any</code> 表示任意类型。
  </p>

  <pre><code>let value: any;

value = "hello";
value = 100;
value = true;
value = {};
value = [];</code></pre>

  <p>
    联合类型表示只能在几个指定类型中选择。
  </p>

  <pre><code>let id: string | number;

id = "A1001"; // 正确
id = 1001;    // 正确
id = true;    // 错误</code></pre>

  <p>
    二者区别可以概括为:
  </p>

  <ol>
    <li><code>any</code>:什么类型都可以,限制很少。</li>
    <li><code>string | number</code>:只能是字符串或数字,不允许其他类型。</li>
  </ol>

  <p>
    如果数据只允许几种明确类型,优先使用联合类型,而不是 <code>any</code>。
  </p>

  <hr>

  <h2>十一、什么时候可以临时使用 any</h2>

  <p>
    虽然不建议随意使用 <code>any</code>,
    但在少数情况下,可以临时使用它。
  </p>

  <h3>场景一:暂时不知道数据结构</h3>

  <pre><code>let responseData: any;</code></pre>

  <p>
    例如,某个接口返回的数据结构还没有确定,
    可以临时使用 <code>any</code>。
    但是数据结构确定后,应该尽量改成明确类型。
  </p>

  <h3>场景二:接入旧代码时过渡使用</h3>

  <p>
    如果一个旧项目原来是 JavaScript,
    后面逐步迁移到 TypeScript,
    可能会在过渡阶段看到 <code>any</code>。
    这种情况下,<code>any</code> 可以暂时帮助代码通过类型检查。
  </p>

  <h3>场景三:第三方数据暂时没有类型</h3>

  <p>
    如果第三方数据暂时没有类型定义,也可能临时使用 <code>any</code>。
    但是长期来看,最好还是补充明确的数据类型。
  </p>

  <p>
    当前阶段可以先记住:
    <strong>any 可以临时使用,但不应该成为默认选择。</strong>
  </p>

  <hr>

  <h2>十二、如何减少 any 的使用</h2>

  <p>
    如果知道数据的具体类型,就应该尽量写清楚类型。
  </p>

  <p>
    如果是字符串,使用 <code>string</code>。
  </p>

  <pre><code>let username: string = "jack";</code></pre>

  <p>
    如果是数字,使用 <code>number</code>。
  </p>

  <pre><code>let age: number = 18;</code></pre>

  <p>
    如果是布尔值,使用 <code>boolean</code>。
  </p>

  <pre><code>let isLogin: boolean = true;</code></pre>

  <p>
    如果是对象,使用对象类型、类型别名或接口。
  </p>

  <pre><code>type User = {
  username: string;
  age: number;
};

let user: User = {
  username: "jack",
  age: 18
};</code></pre>

  <p>
    如果一个值允许多种类型,使用联合类型。
  </p>

  <pre><code>let id: string | number = "A1001";

id = 1001;</code></pre>

  <p>
    这些写法都比直接使用 <code>any</code> 更有利于类型检查。
  </p>

  <hr>

  <h2>十三、any 和 unknown 的简单对比</h2>

  <p>
    后面还会学习 <code>unknown</code>。
    这里先做一个简单对比。
  </p>

  <p>
    <code>any</code> 和 <code>unknown</code> 都可以表示暂时不确定的类型。
    但是它们的安全程度不同。
  </p>

  <pre><code>let value: any = "hello";

console.log(value.toUpperCase());</code></pre>

  <p>
    <code>any</code> 允许直接使用这个值的方法。
    TypeScript 不会严格检查这个方法是否安全。
  </p>

  <pre><code>let value: unknown = "hello";

console.log(value.toUpperCase());</code></pre>

  <p>
    <code>unknown</code> 不允许直接这样使用。
    因为 TypeScript 不确定 <code>value</code> 是否真的是字符串。
  </p>

  <p>
    使用 <code>unknown</code> 时,通常要先判断类型。
  </p>

  <pre><code>let value: unknown = "hello";

if (typeof value === "string") {
  console.log(value.toUpperCase());
}</code></pre>

  <p>
    简单来说:
  </p>

  <ol>
    <li><code>any</code>:更自由,但更容易隐藏问题。</li>
    <li><code>unknown</code>:更严格,使用前需要判断类型。</li>
  </ol>

  <p>
    下一节会专门学习 <code>unknown</code>。
  </p>

  <hr>

  <h2>十四、常见错误写法</h2>

  <p>
    下面列出一些初学者容易写错的地方。
  </p>

  <h3>错误一:为了省事到处使用 any</h3>

  <pre><code>let username: any = "jack";
let age: any = 18;
let isLogin: any = true;</code></pre>

  <p>
    错误原因:
    这些变量的类型都很明确,
    没有必要使用 <code>any</code>。
  </p>

  <p>
    更推荐的写法:
  </p>

  <pre><code>let username: string = "jack";
let age: number = 18;
let isLogin: boolean = true;</code></pre>

  <h3>错误二:用 any 代替对象类型</h3>

  <pre><code>let user: any = {
  username: "jack",
  age: 18
};

console.log(user.address.length);</code></pre>

  <p>
    错误原因:
    <code>user</code> 是 <code>any</code> 后,
    TypeScript 很难检查 <code>address</code> 是否真实存在。
  </p>

  <p>
    更推荐的写法:
  </p>

  <pre><code>type User = {
  username: string;
  age: number;
};

let user: User = {
  username: "jack",
  age: 18
};</code></pre>

  <h3>错误三:用 any 代替联合类型</h3>

  <pre><code>let id: any = "A1001";

id = 1001;
id = true;</code></pre>

  <p>
    错误原因:
    如果 <code>id</code> 只允许字符串或数字,
    就不应该允许布尔值。
  </p>

  <p>
    更推荐的写法:
  </p>

  <pre><code>let id: string | number = "A1001";

id = 1001;
// id = true; // 错误</code></pre>

  <hr>

  <h2>十五、完整小示例</h2>

  <p>
    下面通过一个用户数据案例,演示 <code>any</code> 的问题,以及如何使用明确类型替代它。
  </p>

  <pre><code>// 不推荐:使用 any 后,类型检查变弱
let userData: any = {
  username: "jack",
  age: 18
};

console.log(userData.username);
console.log(userData.age);

// 下面代码在编写阶段可能不容易及时发现问题
// console.log(userData.address.length);

// 推荐:使用类型别名描述对象结构
type User = {
  username: string;
  age: number;
};

let user: User = {
  username: "jack",
  age: 18
};

console.log(user.username);
console.log(user.age);

// 如果访问不存在的属性,TypeScript 可以提示错误
// console.log(user.address);

// 如果一个值允许多种类型,优先使用联合类型
let userId: string | number = "U1001";

userId = 1001;
// userId = true; // 错误:userId 只能是 string 或 number

// 如果暂时不确定类型,后续可以考虑使用 unknown
let value: unknown = "hello";

if (typeof value === "string") {
  console.log(value.toUpperCase());
}</code></pre>

  <p>
    这个案例中:
  </p>

  <ol>
    <li><code>userData: any</code> 让类型检查变弱。</li>
    <li><code>User</code> 类型别名可以明确描述用户对象结构。</li>
    <li><code>string | number</code> 比 <code>any</code> 更适合表示编号类型。</li>
    <li><code>unknown</code> 在使用前需要先判断类型,安全性更高。</li>
  </ol>

  <p>
    <code>any</code> 的主要作用是临时绕过类型检查。
    但是在能写出明确类型的情况下,应该尽量使用明确类型。
  </p>

  <hr>

  <h2>十六、本节总结</h2>

  <p>
    本节学习了 TypeScript 中的 <code>any</code>。
  </p>

  <ol>
    <li><code>any</code> 表示任意类型。</li>
    <li>被标注为 <code>any</code> 的变量可以保存任何类型的数据。</li>
    <li><code>any</code> 会让 TypeScript 的类型检查变弱。</li>
    <li><code>any</code> 可能隐藏运行时错误。</li>
    <li><code>any</code> 会影响编辑器的准确提示。</li>
    <li><code>any[]</code> 表示数组中可以保存任意类型的数据。</li>
    <li>对象使用 <code>any</code> 后,TypeScript 很难检查属性是否正确。</li>
    <li>函数参数使用 <code>any</code> 后,调用时容易传入不合适的数据。</li>
    <li>如果只允许几种明确类型,应该优先使用联合类型。</li>
    <li>如果对象结构明确,应该优先使用对象类型、类型别名或接口。</li>
    <li><code>any</code> 可以临时使用,但不应该成为默认选择。</li>
    <li><code>unknown</code> 比 <code>any</code> 更严格,下一节会专门学习。</li>
  </ol>

</body>
</html>
相关推荐
白狐_7982 小时前
408数据结构:中缀转后缀与操作符栈容量——真题精讲
前端·javascript·数据结构
谷哥的小弟2 小时前
TypeScript在Vue3中的常见写法
前端·javascript·typescript
njsgcs2 小时前
链轮 平键和键槽的标准尺寸 计算 typescript
typescript·机械工程
mONESY3 小时前
用 useRef 管理 Worker 线程,让你的页面不再卡顿
javascript
满栀5856 小时前
请求拦截、响应拦截、业务错误统一处理
前端·typescript·anti-design-vue
vx-程序开发7 小时前
django医院预约挂号系统---附源码23353
java·javascript·spring boot·python·eclipse·django·php
宿6747 小时前
tsconfig.node.json
前端·javascript·vue.js
lilian2337 小时前
Harmony os 技术实战|拼豆制图10:把取消、解析失败和保存失败写成可恢复状态机
java·javascript·华为·harmonyos
只会cv的小前端8 小时前
七巧低代码表单JS脚本教学
开发语言·javascript·低代码