TypeScript基础之常见类型(基本类型、any、unknown、void、never)

对于null, undefined类型

默认情况下nullundefined是所有类型的子类型, 即可以把nullundefined赋值给其他类型。

注意: tsconfig.json指定了"strictNullChecks":true , nullundefined 只能赋值给 anyunknown 和它们各自的类型, undefined可以赋值给void类型;

以下代码在严格模式下("strictNullChecks":true )下运行:

let v: void = undefined;   // 没毛病

let v1: void = null;   // Type 'null' is not assignable to type 'void'.  

let notSure: unknown = 'unknown';
let a: any = 18;
let n: null = null;
let u: undefined = undefined;

a = n;   // 没毛病
a = u;   // 没毛病

notSure = n;    // 没毛病
notSure = u;    // 没毛病

n = u;      // Type 'undefined' is not assignable to type 'null'.

以下代码在非严格模式下(指定了"strictNullChecks":false), 可以把nullundefined赋值给其他类型

// null和undefined赋值给number  
let num: number = 18;
num = null;
num = undefined;

// null和undefined赋值给string 
let str: string = 'hello';
str = null;
str = undefined;

// null和undefined赋值给boolean 
let bool: boolean = false;
bool = null;
bool = undefined;

// null和undefined赋值给bigint
let big: bigint = 10n;
big = null;
big = undefined;

// null和undefined赋值给symbol
let sym: symbol = Symbol('foo');
sym = null;
sym = undefined;

// null和undefined赋值给object
let obj: object = {};
obj = null;
obj = undefined;

注意: 如果出现BigInt literals are not available when targeting lower than ES2020. 需要把ypeScript编译器目标设置为es2020

对于number、string、symbol、boolean、bigint 原始类型

在赋值过程中改变类型是不被允许的。
虽然numberbigint 都表示数字,但是这两个类型不兼容。

let num: number = 100;
num = 'hello';      // Type 'string' is not assignable to type 'number'.

let str: string = 'xman';
str = symbol('1');  // Type 'symbol' is not assignable to type 'string'.

let sym: symbol = Symbol('foo');
sym = false;        // Type 'boolean' is not assignable to type 'symbol'.

let big: bigint = 10n;
big = 1;            // Type 'number' is not assignable to type 'bigint'.

let obj: object = {};
obj = 'xxx';        // Type 'string' is not assignable to type 'object'.

对于Number、String、Symbol、Boolean、Bigint包装类型

注意: Number、String、Symbol、Boolean、Bigint是包装类型, 而number、string、symbol、boolean、bigint 是原始类型,不要混淆。
从类型兼容性上看, 原始类型兼容对应的对象包装类型, 对象类型不兼容对应的原始类型。
如:

let str: string = 'hello';
let Str: String = String('hello');

str = Str;
// Type 'String' is not assignable to type 'string'.
// 'string' is a primitive, but 'String' is a wrapper object. Prefer using 'string' when possible.

Str = 'hello';   // 没毛病

对于any类型

在TypeScript中, 任何类型都可以被归为 any 类型,这让 any 类型成为了类型系统的顶级类型.

  • any在赋值过程中可以随意改变类型:
let a: any = 'any';
let notSure: unknown = 'unknown';
let v: void = undefined;
let ne: never;

// 以下都没毛病
a = ne;
v = a;
a = v;
a = notSure;    
a = 100;
a = 10n;
a = false;
a = undefined;
a = null;
a = [];
a = {};
  • 如果一个类型为any类型, 那么访问其任何类型、调用任何方法在编译时都没毛病。但在运行时就可能出问题或者报错,所以一定要慎用any类型。
let a: any = 'anything';
console.log(a.name);
console.log(a.info.address);
a.setName('xman');
a.getName();
  • 如果定义的时候没有赋值, 不管之后有没有赋值,都会被推断为 any 类型 而完全不被类型检查:
let a;    // 推断为any类型
a = 'hello';
a = false;
a = 100;
a = undefined;
a = null;
a = {};

最后总结下: 使用 any,我们将会失去通常由 TypeScript 的静态类型系统所给予的所有保护。因此,如果我们无法使用更具体的类型或 unknown,则只能将其用作最后的手段。 一定要慎用any类型。

对于unknown类型

unknownany都是TypeScript中的顶级类型。 所以所有类型都可以分配给unknown:

let value: unknown;

value = true; 
value = 42; 
value = "Hello World"; 
value = []; 
value = {}; 
value = Math.random; 
value = null; 
value = undefined; 
value = new TypeError(); 
value = Symbol("type"); 

unknown 类型只能被赋值给 any 类型和 unknown 类型本身。

let value: unknown;

let value1: unknown = value;    // 没毛病
let a: any = value;             // 没毛病

let num: number = value;        // Type 'unknown' is not assignable to type 'number'.

TypeScript 不允许我们对类型为 unknown 的值执行任意操作。相反,我们必须首先执行某种类型检查以缩小我们正在使用的值的类型范围。

function foo (value: unknown) {
  let val = value.toFixed(2);   // Property 'toFixed' does not exist on type 'unknown'.
}

我们可以使用如下方法进行缩小未知范围:

  • 类型断言
function foo (value: unknown) {
  let val = (value as number).toFixed(2);    
}
  • 使用typeof
function foo (value: unknown) {
  if (typeof value === 'number') {
      let val = value.toFixed(2);  
  }
    
}
  • 自定义类型保护 (is 关键字)
    通过 is 关键字将类型范围缩小为 number 类型
const isNumber = (val: unknown): val is number => typeof val === 'number';
function foo (value: unknown) {
  if (isNumber(value)) {
      let val = value.toFixed(2);  
  }
}

对于never类型

never类型表示的是那些永不存在的值的类型
never类型同null和undefined一样,也是任何类型的子类型,也可以赋值给任何类型, 但是没有类型是never的子类型或者可以赋值给never类型(除了never本身之外),即使any也不可以赋值给never。
never 类型是 TypeScript 中的底层类型。它自然被分配的一些例子:

  • 一个从来不会有返回值的函数(如:如果函数内含有 while(true) {});
let ne = (() => { while(true) {} })();      // ne 为never类型 
  • 一个总是会抛出错误的函数(如:function foo() { throw new Error(‘Error’) },foo 的返回类型是 never);
let ne = (() => { throw new Error("异常"); })();    // ne 为never类型 
let ne: never;
let ne1: never;
let num: number = 1;
num = ne;       // 没毛病

ne = 100;       // Type 'number' is not assignable to type 'never'.
ne = ne1;       // 没毛病   

对于void类型

JavaScript中的void
JavaScript中的void是一个运算符, 对给定的表达式进行求值,然后返回 undefined。具体可看MDN void

let i = void 100;
i === undefined;    // true

我们为什么需要这样的东西?首先在早期,人们能够覆盖 undefined 并给它一个实际值。 void 总是返回 real undefined。
其次,这是一种调用立即调用函数的好方法:

void function() {
  console.log('What')
}()

TypeScript中的void
TypeScript 中的 void 是 undefined 的子类型。 JavaScript 中的函数总是返回一些东西。要么它是一个值,要么是 undefined.
因为没有返回值的函数总是返回undefined,下面函数返回数据类型定义为void类型,告诉开发人员这个函数返回 undefined:

declare function iTakeNoParameters (x: number): void;

void用作参数声明

declare function iTakeNoParameters (x: void): void;

iTakeNoParameters();
iTakeNoParameters(undefined);
iTakeNoParameters(void 100);

voidundefined有什么区别呢?
区别在于 作为返回类型的void可以用不同的类型替换,以允许高级回调模式:

function doSomething (callback: () => void) {
  let c = callback();   // 此时c为void类型 
  // ...  
}

// 返回number类型 
function aNumberCallback (): number {
  return 2;  
}

doSomething(aNumberCallback); 

如果你想确保传递只返回 undefined 的函数(如“nothing”),请确保调整你的回调方法签名:

function doSomething (callback: () => undefined) {
  let c = callback();   // 此时c为void类型 
  // ...  
}

// 返回number类型 
function aNumberCallback (): number {
  return 2;  
}

doSomething(aNumberCallback);   
// Argument of type '() => number' is not assignable to parameter of type '() => undefined'.
// Type 'number' is not assignable to type 'undefined'.

此外, 函数如果没有显式的返回undefined的,我们需要定义成void类型,而不是undefined类型。否则将报错。

function foo (): void {
  console.log('---foo----');
}


// A function whose declared type is neither 'void' nor 'any' must return a value.
function foo1(): undefined {
  console.log('---foo1----');  
}
foo1();


// 没毛病
function foo2 (): undefined {
  return undefined;
}

以上ts代码均在 https://www.typescriptlang.org/play 上运行过,版本为4.7.2。
最后, 如有错误,欢迎各位大佬指点!感谢!

参考资料

https://fettblog.eu/void-in-javascript-and-typescript/
https://juejin.cn/post/6844903866073350151

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的。 TypeScript 中的 `any` 类型表示一个可以是任何类型的值。它可以用于避免类型检查,或者在你还没有确定类型的情况下使用。但是,使用 `any` 类型会放弃 TypeScript 带来的类型检查的所有优势,因此在能使用更精确类型的地方应尽量避免使用 `any`。 TypeScript 中的 `unknown` 类型表示一个未知的类型。它比 `any` 类型更加严格,因为在使用前需要进行类型检查。在某些情况下,你可能希望接收一个未知的值,但是又不想使用 `any` 类型,此时就可以使用 `unknown` 类型TypeScript 中的 `never` 类型表示永远不会有返回值的函数的返回值类型。它也可以表示永远不会被执行的代码块的类型。例如,当某个函数的所有可能执行路径都会抛出异常时,它的返回值类型就可以是 `never`。 希望这对你有所帮助。 ### 回答2: TypeScript中的`any`、`unknown`和`never`是三种特殊的类型。 1. `any`类型表示任何类型的值都可以赋值给它。它相当于取消了类型检查,可以在编写代码时快速推进开发,但也容易引入潜在的类型错误。使用`any`类型时需要慎重,最好在必要情况下使用,例如在需要与非TypeScript代码进行交互或在临时情况下。 2. `unknown`类型TypeScript 3.0中引入的一种类型。与`any`相比,`unknown`类型提供了更加安全的动态类型。当我们不确定变量的类型时,可以使用`unknown`类型来保持类型的不确定性。在使用`unknown`类型的值时,我们必须首先进行类型检查或类型断言,以将其转换为更具体的类型。与`any`不同,`unknown`类型不会自动允许我们执行任意操作。这种类型的引入提高了代码的类型安全性,减少了潜在的类型错误。 3. `never`类型表示它永远不会发生的类型,即表示从不返回值的函数的返回类型以及永远无法完成的操作的结果类型。例如,在一个函数中抛出了异常,或者存在无限循环。使用`never`类型可以更好地定义某些情况下的函数或操作的返回类型,同时帮助我们避免潜在的逻辑错误。 ### 回答3: TypeScript是一种静态类型的编程语言,它可以在JavaScript的基础上添加静态类型检查和一些其他特性。在TypeScript中有三种特殊的类型:any、unknown和never。 any类型表示任意类型,它可以用来表示任何类型的值。使用any类型可以绕开类型检查,编译器不会对any类型的值进行类型检查和推断。any类型的变量可以接受任何类型的值,因此在使用any类型时需要特别小心,因为它可能导致类型错误和运行时错误。 unknown类型也表示任意类型,但它比any类型更严格。当使用unknown类型时,编译器会要求进行类型检查和类型断言,以确保类型安全。unknown类型的变量不能直接赋值给其他类型的变量,必须经过类型断言或类型检查后才能进行赋值。这种类型更适合在编写通用代码或处理动态类型的情况下使用,相比any类型unknown类型提供了更加严格的类型安全。 never类型表示永远不会发生的类型。它通常会用在函数的返回类型中,表示该函数永远不会正常返回。例如,一个会抛出异常或进入无限循环的函数的返回类型可以设为never。同时,never类型也可以用来处理不可到达的代码块,例如一个带有无限循环的函数的后续代码块。 总而言之,在TypeScript中,any类型unknown类型都表示任意类型,但unknown类型更加严格,并且要求进行类型检查和类型断言。而never类型表示永远不会发生的类型,通常用于函数的返回类型或不可到达的代码块。使用这些类型要谨慎,并且根据实际需求来选择合适的类型

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值