TS入门——快速上手(一)

前言

TypeScript(TS)是什么?

TypeScript 是 JavaScript 的超集,这意味着 JS 中能实现的各种操作和语法,在 TS 中都可以实现。TS 添加了可选的静态类型检查 ,使得开发者可以在开发阶段就发现类型错误,从而提高代码质量和可维护性。此外,TypeScript 还包含了对类、接口、命名空间等面向对象编程特性的支持。

简单来讲,TypeScript(TS)就是为 JS 提供了一个类型限定,它的主要目的是让 js 代码更加健壮和可维护,在学习 TS 时,最重要的一环就是理解并熟练运用类型系统。今天咱们先来简单上手一下TS和了解它的基本类型

正文

TS安装

less 复制代码
npm i -g typescript  // 全局安装 TypeScript

如果想要运行 ts 则可以安装 ts-node。

less 复制代码
npm i -g ts-node  // 全局安装 ts-node

ts-node 是一个实用工具,允许你在 Node.js 中直接运行 TypeScript 文件。例如ts-node add.ts,将执行 app.ts 文件中的代码,而无需显式地使用 tsc 命令将其编译为 JavaScript。

TS类型

基本类型

和 JS 保持一致,比如 stringnumberboolean。在 TS 中,你可以显式地为变量指定类型:

ini 复制代码
let name: string = "hello";
let age: number = 22;
let isSingle: boolean = true;
let a:symbol=Symbol();
let b:bigint=123n;

let u: undefined = undefined; // 表示变量尚未被赋值
let n: null = null; // 显示将值设为空
null 和 undefined

nullundefined 可以赋值给任何类型,此时可以理解为它们是所有类型的子类型。如果你在 tsconfig.json 中开启了 strictNullChecks 选项,nullundefined 只能赋值给 void 或它们各自的类型。

默认未开启 strictNullChecks 选项

ini 复制代码
let name: string = "John";
name = null;        // 没有报错
name = undefined;   // 也没有报错

开启了 strictNullChecks 选项

ini 复制代码
let name: string = "John";
name = null;        // 报错:不能将 null 赋值给 string 类型
name = undefined;   // 报错:不能将 undefined 赋值给 string 类型

let nullableName: string | null = "John";
nullableName = null;  // 这样就可以,因为类型包含了 null

在启用了 strictNullChecks 的情况下:

  • 只有明确标注为 nullundefined 的类型(例如 string | nullnumber | undefined)才能接收 nullundefined 作为值。
  • 其他类型的变量(如纯粹的 stringnumber)不能被赋值为 nullundefined

void 类型

void 类型通常用于函数没有返回值的情况,它表示没有任何类型

c 复制代码
function logMessage(message: string): void {
  console.log(message);
}

any类型

1、代表任何类型,any 可以赋值成任意类型的值,可以赋给其他类型

ini 复制代码
let x: any;
x = 1;
x = "hello";
let y: boolean = true;
y = x;

2、在 ts 文件中可以创建一个 tsconfig.json 文件进行配置,其中noImplicitAny 是一个重要的编译选项,默认值为 false ,它控制着 TypeScript 编译器是否允许隐式的 any 类型。当你设置 "noImplicitAny": false 时,意味着你允许 TypeScript 编译器接受隐式的 any 类型。

json 复制代码
"compilerOptions": {
    "noImplicitAny": true // 不允许any
}

如果 noImplicitAny 设置为 true,那么这段代码在编译时会产生一个警告或错误,指出 xy 的类型没有显式指定。编译器会提示你需要为这些变量提供类型注解。

不推荐使用any!这会让TypeScript变为"AnyScript"(失去TS类型保护的优势)

因为当值的类型为any时,可以对该值进行任意操作,并且不会有代码提示。

尽可能的避免使用any类型,除非临时使用any来'避免'书写很长、很复杂的类型!

其他隐式具有any的情况:

1、声明变量不提供类型也不提供默认值

2、函数参数不加类型。

unknown类型

unknown 类型是一个更安全的 any 类型。与 any 不同,在将 unknown 类型赋值给其他类型之前,必须先进行类型检查或`类型断言

javascript 复制代码
function processValue(value: unknown) {
  if (typeof value === "string") {
    console.log(`String value: ${value}`);
  } 
  else if (typeof value === "number") {
    console.log(`Number value: ${value}`);
  } 
  else if (typeof value === "object" && value !== null) {
    console.log("Object value:", value);
  } 
  else {
    console.log("Unknown type");
  }
}

processValue("Hello, world!"); // 输出: String value: Hello, world!
processValue(42);              // 输出: Number value: 42
processValue({ id: 1 });       // 输出: Object value: { id: 1 }
processValue(true);            // 输出: Unknown type

使用之前你若不进行类型检查或类型断言就会报错

因此 unknown 提供了比 any 更好的类型安全保障。

never 类型

never 类型表示永远不会有值的类型。通常用于表示那些总是会抛出错误不会有返回值的函数。因此被赋值会报错,哪怕是 any

typescript 复制代码
function error(message: string): never {
  throw new Error(message);
}

never 也可以表示不可能的类型,例如当类型联合被完全穷尽时:

typescript 复制代码
type Animal = "cat" | "dog" | "dolphin";

function handleAnimal(animal: Animal) {
  switch (animal) {
    case "cat":
      console.log("It's a cat.");
      break;
    case "dog":
      console.log("It's a dog.");
      break;
    case "dolphin":
      console.log("It's a dolphin.");
      break;
    default:
      // 这里的 never 类型确保我们已经处理了所有可能的情况
      const exhaustiveCheck: never = animal;
      throw new Error(`Unhandled case: ${exhaustiveCheck}`);
  }
}

as类型断言

javascript 复制代码
const aLink: HTMLAnchorElement
const aLink=document.getElementById('link')as HTMLAnchorElement

1、使用as关键字实现类型断言。

2、关键字as后面的类型是一个更加具体的类型(HTMLAnchorElement是HTMLElement的子类型)

3、通过类型断言,aLink的类型变得更加具体,这样就可以访问a标签特有的属性或方法了。

另一种语法,使用<>语法,这种语法形式不常用知道即可

ini 复制代码
const aLink=<HTMLAnchorElement>document.getElmentById('link')

tips:在浏览器的控制台,通过console.dir()打印DOM元素,在属性列表后面,即可看到该元素的类型。

再来个例子:

typescript 复制代码
let value: unknown = "Hello, TypeScript";

// 使用类型断言将 unknown 类型的值转换为 string 类型
let strValue: string = value as string;

console.log(strValue.toUpperCase()); // 输出: HELLO, TYPESCRIPT

类型推论

在TS中,某些没有明确指出类型的地方,ts的类型推论机制会帮助提供类型换句话说:由于类型推论的存在,这些地方,类型注解可以省略不写!

发生类型推论的2种场景:

1、声明变量并初始化时

2、决定函数返回值时

typescript 复制代码
let age:number
let age=18

function add(num1:number,num2:number):number
function add(num1:number,num2:number){
return num1+num2
}

推荐:能省略类型注解的地方就省略,如果不知道类型,可以通过鼠标放在变量名称上,利用vscode的提示来查看类型

类型别名

为类型创建一个新的名称,用关键字 type

1、使用type关键字来创建类型别名。

2、类型别名(比如,此处的CustomArray)可以是任意合法的变量名称

3、创建类型别名后,直接使用该类型别名作为变量的类型注解即可。

函数类型

单独指定参数、返回值的类型

函数声明方式:

typescript 复制代码
function add(num1:number,num2:number):number{
return num1+num2
}

函数表达式方式:

typescript 复制代码
const add=(num1:number,num2:number):number=>{
return num1+num2
}
同时指定参数、返回值的类型
typescript 复制代码
const add:(num1:number,num2:number)=>number =(num1,num2)=>{
return num1+num2
}
空类型:void
c 复制代码
function greet(name:string):void{
console.log('Hello',name)
}
可选参数

在可传可不传的参数名称后面添加?(问号)

sql 复制代码
function mySlice(start?:number,end?:number):void{
console.log('起始索引',start,'结束索引:',end)
}

对象类型

typescript 复制代码
let person:{name:string;age:number;sayHi():void;greet(name:string):void}={
name:'刘老师',
age:18,
sayHi(){},
greet(name){}
}

1、如果一行代码只指定一个属性类型(通过换行来分隔多个属性类型),可以去掉;(分号)

2、方法的类型也可以使用箭头函数形式(比如:{sayHi:()=>void})

可选属性

typescript 复制代码
function myAxios(config:{url:string;method?:string}){
console.log(config)
}

可选属性的语法与函数可选参数的语法一致,都用问号来表示

接口

当一个对象类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到复用的目的。

typescript 复制代码
interface IPerson{
name:string
age:number
sayHi():void
}
let person:IPerson={
name:'jack',
age:19,
sayHi(){}
}

1、使用interface关键字来声明接口

2、接口名称可以是任意合法的变量名称。

3、声明接口后,直接使用接口名称作为变量的类型。

4、因为每一行只有一个属性类型,因此,属性类型后没有;(分号)

interface(接口)和type(类型别名)的对比:

相同点:都可以给对象指定类型。

不同点:

1、接口只能为对象指定类型

2、类型别名:不仅可以为对象指定类型,实际上可以为任意类型指定别名。

type NumStr =number|string

接口继承

extends

如果两个接口之间有相同的属性或者方法,可以将公共的属性或者方法抽离出来,通过继承来实现复用。

typescript 复制代码
interface Point2D{x:number;y:number}
interface Point3D extends Point2D {z:number}

1、使用extends(继承)关键字实现了接口Point3D继承Point2D.

2、继承后,Point3D就有了Point2D的所有属性和方法(此时,Pointe3D同时有xyz三个属性)

元组

使用number[]的缺点:不严谨,因为该类型的数组中可以出现任意多个数字。

更好的方式:元组(Tuple)

元组类型是另一种类型的数组,它准确的知道包含多少个元素,以及特定索引对应的类型

typescript 复制代码
let position: [number,number]=[39.5427,116.2317]

1、元组类型可以准确的标记出有多少个元素,以及每个元素的类型。

2、该示例中,元素有两个元素,每个元素的类型都是number.

同样,元组类型用于表示已知数量和类型的元素的数组。与数组类型不同,元组中的每个元素类型可以不同。

typescript 复制代码
let tuple: [string, number, boolean] = ["hello", 42, true];

元组的长度是固定的,并且每个位置上的类型是确定的。这在需要表示固定结构的数据时非常有用,例如函数返回多个值的情况。当 push 的元素超出时类型必须是已有的,否则报错:

字面量类型

使用模式:字面量类型配合联合类型一起使用

使用场景:用来表示一组明确的可选值的列表。

比如,在贪吃蛇游戏中,游戏的方向的可选值只能是上下左右的任意一个

css 复制代码
function changeDirection(direction:'up'|'down'|'left'|'right'){
console.log(direction)
}

解释:参数direction的值只能是up/down/left/right中的任意一个

优势:相比于string类型,使用字面量类型更加精确、严谨

枚举类型

枚举的功能类似于字面量类型+联合类型组合的功能,也可以表示一组明确的可选值。

枚举:定义一组命名常量。它描述一个值,该值可以是这些命名常量中的一个

css 复制代码
enum Direction{Up,Down,left,Right}

function changeDirection(direction:Direction){
console.log(direction)
}

1、使用enum关键字定义枚举。

2、约定枚举名称,枚举中的值以大写字母开头

3、枚举中的多个值之间通过逗号分隔

4、定义好枚举后,直接使用枚举名称作为类型注解。

注意:形参direction的类型为枚举Direction,那么,实参的值就应该是枚举Direction成员的任意一个,类似于JS中的对象,直接通过点.语法访问枚举成员。

数字枚举

问题:我们把枚举成员作为了函数的实参,它的值是什么呢?

注意:枚举成员是有值的,默认为:从0开始自增的数值

我们把枚举成员的值为数字的枚举称为数字枚举,当然也可以给枚举中的成员初始化值

css 复制代码
//Down-> 11、left->12、Right->13
enum Direction {Up=10,Down,Left,Right}
字符串枚举

枚举成员的值是字符串

ini 复制代码
enum Direction{
Up='Up',
Down='Down'
}

注意:字符串枚举没有自增长行为,因此,字符串枚举的每个成员必须有初始值。

枚举的特点及原理

枚举是ts为数不多的非javaScript类型级扩展(不仅仅是类型)的特性之一。

因为:其他类型仅仅被当作类型,而枚举不仅用作类型,还提供值。

也就是说,其他的类型会在编译为js代码时自动移除,但是,枚举类型会被编译为js代码!

一般情况下,推荐使用字面量类型+联合类型组合的方式,因为相比枚举,这种方式更加直观、简洁、高效。

TS中的typeof运算符

众所周知,JS中提供了typeof操作符,用来在JS中获取数据的类型。

实际上,TS也提供了typeof操作符:可以在类型上下文中引用变量或属性的类型(类型查询)

使用场景:根据已有变量的值,获取该值的类型,来简化书写。

css 复制代码
let p={x:1,y:2}
function formatPoint(point:{x:number;y:number}){}
formatPoint(p)

function formatPoint(point:typeof p){}

1、使用typeof操作符来获取变量P的类型,结果与第一种(对象字面量的类型)相同。

2、typeof出现在类型注解的位置(参数名称的冒号后面)所处的环境就在类型上下文(区别于Js代码)。

3、注意:typeof 只能用来查询变量或属性的类型,无法查询其他形式的类型(比如,函数调用的类型)

结尾

好啦,今天的分享就到这里结束了,今天介绍了一下TS简单的基本类型,相信小伙伴们应该都理解了叭,还有进阶的更复杂的TS的高阶类型体操我就下期在和大家分享哈!

相关推荐
Zack No Bug3 分钟前
解决报错:rror: error:0308010C:digital envelope routines::unsupported
前端·javascript·vue.js
QTX1873013 分钟前
原生JS和CSS,HTML实现开屏弹窗
javascript·css·html
rhythmcc1 小时前
【GoogleChrome】在开发者工具中修改js、css并生效
开发语言·javascript·css
凌虚1 小时前
Web 端语音对话 AI 示例:使用 Whisper 和 llama.cpp 构建语音聊天机器人
前端·人工智能·后端
小宇python1 小时前
Web应用安全入门:架构搭建、漏洞分析与HTTP数据包处理
前端·安全·架构
珹洺1 小时前
从 HTML 到 CSS:开启网页样式之旅(二)—— 深入探索 CSS 选择器的奥秘
前端·javascript·css·网络·html
竺梓君2 小时前
JavaScript内存管理机制解析
javascript·全栈
liro2 小时前
CSS盒子模型
前端
热爱前端的小张2 小时前
包管理器
前端
冰冻果冻2 小时前
vue--制作随意滑动的相册
前端·javascript·vue.js