TypeScript类型any、unknown、never和void使用场景区别

作者:纸飞机

时间:2026-10-26

浏览:603

本文详细解析TypeScript中any、unknown、never和void四种类型的核心区别与适用场景。any跳过类型检查,适用于JS迁移;unknown提供类型安全,需先推断;never用于穷举检查和永不返回的函数;void表示无返回值。通过对比示例,帮助开发者避免类型陷阱,写出更安全的代码。

文章目录

前言

不知TypeScript初学者是否如我般,常被any、unknown、never与void这几种类型弄得困惑不已?若你亦有此感,请随本文彻底厘清四者的差异。

any

首推any类型,想必从JavaScript转战TypeScript的开发者对此并不陌生,它堪称将JavaScript重构为TypeScript的利器,甚至有人因过度依赖any,硬是把TypeScript写成了AnyScript。

用法

一旦变量被定义为any类型,TypeScript便会跳过对这个变量的类型检查:

let something: any = 'Hello World!' 
something = 18 // ok! ts不会管any的类型检查
something = true // ok! ts不会管any的类型检查

通常,若something初始化为字符串,便不可赋值为number或boolean,但因其声明为any,TypeScript便无视该对象类型检查。此外,你可随意访问此any对象的任意属性,即便它们并不存在:

let something: any = 'Hello World!'
something.notExistMethod() // ok! 
something.notExistProperty.name() // ok!

上述代码显示,我们可以访问any类型对象的任意属性,且此any具备传递性特性,即something后接任意属性访问,其类型均为any。

使用场景

any的典型应用场景如下:

  • JS迁移TS:此时使用any可加速快速推进,无需陷入无尽类型错误。需注意的是,any仅作为临时过渡方案,最终目标应是确保代码中any出现频率最低。
  • 不关心对象类型:例如实现print函数,其底层调用console.log,此时无需关心传入的具体数据类型,只需将其传递给console.log函数即可,故可将参数类型设为any。

类型缺失或补全困难:此情况多见于使用第三方JS库时,因无法获知导出函数的具体类型,需定义全局类型垫片:

// shim.d.ts
declare module "unknown-type-lib" {
  export function someFunction(input: string): any
}

注意:尽管any便捷,但仍需设法避免代码中出现any类型,因为any会跳过所有类型检查,带来潜在安全风险。最坏情形下,若代码除any外无其他有意义类型,不如直接编写JavaScript代码。既然选择了TypeScript,便期望其带来实质收益,故面对难编类型,最佳策略非写any,而是咨询资深工程师或查阅资料解决。

unknown

前文提及any会跳过类型检查,这为日后维护埋下巨大隐患。为化解any问题,TypeScript在3.0版本引入unknown类型,可视为类型安全的(type-safe)any。

用法

与any相同,任何类型均可赋值给unknown类型对象:

let vAny: any = 'Hello World!' // ok! any对象接受任何类型
let vUnknown: unknown = 'Hello World!' // ok! unknown对象接受任何类型的对象

与any不同,unknown类型对象不可直接赋值给其他非unknown或any类型对象,且不可访问其任何属性:

let vAny: any = 'Hello World!'
let vUnknown: unknown = 'Hello World!'
let vNumberForAny: number = vAny // ok! any可以直接赋值给其它任意类型
let vNumberForUnknown: number = vUnknown // error! unknown不可以直接赋值给其它非any和unknown类型的对象
vAny.toLocaleLowerCase() // ok! any可以访问所有的属性
vUnknown.toLocaleLowerCase() // error! unknown对象不可以直接访问上面的属性

如何运用unknown类型变量?答案简单:需先推断对象类型方可使用,推断方式多样,包括typeof与as assertion等type guard手段:

let vUnknown: unknown = 'abc'
// 使用typeof推断出vUnknown的类型是string
if (typeof vUnknown === 'string') {
    vUnknown.toLocaleUpperCase() // ok! 因为能进入这个if条件体就证明了vUnknown是字符串类型!
}
let vNumberForUnknown: number = vUnknown as number // unknown类型一定要使用as关键字转换为number才可以赋值给number类型

使用场景

因unknown基本可替代any,故在任何any适用场景,均应优先选用unknown。使用unknown后,既允许对象存储任意类型变量,又要求使用者先进行类型推断。

never

never不如前述类型常用,部分同学甚至不知其存在意义。我们知道TypeScript在解析代码时会进行类型推断,随着代码流深入,类型会从宽泛(如any)推断至具体,直至终点——即不存在、不可能发生的类型,也就是类型系统的底部类型(bottom type),而never正是TypeScript的底部类型。

用法

never类型仅接受never类型对象,即便万金油any类型亦不可赋值给never类型。

let vAny: any = 1
let vNever: never =  vAny // error! never除了自己谁不都接受!

通常,当我们想表示某函数永远不会返回时,可使用never类型,例如下面示例:

// 因为这个是无限循环,我们可以使用never作为返回值表示它永远不会返回
function foreverLoop(): never {
  while(true) {}
}
// 因为这个函数会抛出异常,所以也是不会返回的
function crashFunc(): never {
  throw new Error('this function will crash')
}

使用场景

never类型最大作用在于协助我们对类型进行exclusive check,例如下面示例:

interface QA {
    kind: 'qa'
    bug: number
}
interface Developer {
    kind: 'developer'
    hair: number
}
type TechDude = QA | Developer
function printTechDude(h: TechDude) {
    if (h.kind === 'qa') {
        console.log(h.bug)
    } else if (h.kind === 'developer') {
        console.log(h.hair)
    } else {
        let exclusiveCheck: never = h // 由于这个代码永远也到达不了,所以h的类型被自动推断为never
    }
}

上述代码目前无误,但若某日新增PM类型,却忘记在printTechDude函数中处理该新类型,则代码会报错:

interface QA {
    kind: 'qa'
    bug: number
}
interface Developer {
    kind: 'developer'
    hair: number
}
interface PM {
    kind: 'pm'
    features: number
}
// TechDude多了一个PM类型
type TechDude = QA | Developer | PM
function printTechDude(h: TechDude) {
    if (h.kind === 'qa') {
        console.log(h.bug)
    } else if (h.kind === 'developer') {
        console.log(h.hair)
    } else {
        let exclusiveCheck: never = h // error! 因为PM类型不可以赋值给never类型
    }
}

报错原因在于TechDude类型在else代码体内已被TypeScript收拢为PM类型,故不再是never类型。要消除此错误,需在printTechDude函数内额外增加else if(h.kind === 'pm')判断:

function printHuman(h: TechDude) {
    if (h.kind === 'qa') {
        console.log(h.bug)
    } else if (h.kind === 'developer') {
        console.log(h.hair)
    } else if (h.kind === 'pm') {
        console.log(h.features)
    }else {
        let exclusiveCheck: never = h
    }
}

正因exclusive check的存在,我们方能在类型变化时及时察觉,避免问题遗留至线上环境。

void

void可理解为null与undefined的联合类型,表示空值。

用法

我们通常不会声明某值为void类型,因其表示该值只能是undefined或null(strictNullChecks未指定时):

let vVoid: void = undefined

void更常见场景是表示某函数无任何返回值:

function noReturnValue(): void {
  console.log('hello')
  // 代码没有任何返回值,所以这个函数的返回值是void
}

使用场景

此处仅说明void与never之别。void表示空值,即null或undefined,而never则表示永远都不会出现的值。

总结

本文通过示例介绍了TypeScript中易混淆的any、unknown、never及 void,希望能助有需要者解惑,更多TypeScript类型使用场景资料请关注本站其他相关文章!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章