TS学习-2

常用类型和语法

1.any

任意类型,⼀旦将变量类型限制为any,意味着放弃了对该变量的类型检查。

let a:any
//以下赋值无警告
a=100
a='你好'
a=false

//隐式any
let b

注意:any类型的变量,可以赋值给任意类型的变量

let c:any
c=9

let x:string
x=c //没有报错

2.unknown

未知类型,适用于:起初不确定数据的具体类型,要后期才能确定

  1. unknown可以理解为一个类型安全的any
let a:unknown
//不会报错
a=100
a=false
a='你好'

//设置x的数据类型为string
let x:string
x=a//不能将类型'unknown"分配给类型”string“
  1. unknown会强制开发者在使用之前进行类型检查
//第一种
if(typeof a==='string'){
    x=a
}

//第二种: 加断言
x=a as string

//第三种
x=<string>a
  1. 读取any类型数据的任何属性都不会报错,unknown相反
let str1:string
str1.toUpperCase()//不报错

let str2:any
str2.toUpperCase()//不报错

let str3:unknown
str3.toUpperCase()//报错
//强制断言
(str3 as string).toUpperCase()

3.never

never的含义是:任何值都不是,即:不能有值,例如undefinednul
0都不行!

never限制函数返回值的

function demo():never{
}

注意:ts中没有指明任何返回值的函数调用结束也会返回undefined

function throwError(str:string):never{
    //程序抛出异常,并立刻结束对函数的调用
    throw new Error('程序异常退出'+str)
}

4.void

void的含义是空,即:函数不返回任何值,调用者也不应依赖其返回值进行任何操作!限制函数返回值的,不能对变量进行限制。

  1. void通常用于函数返回值声明
function logMessage(msg:string):void{
    console.log(msg)
}
logMessage('你好')

注意:没有编写return指定函数返回值,所以logMessage函数是没有显式
返回值的,但会有一个隐式返回值,是undefined,虽然函数返回类型为void,但也是可以接受undefined的,简单记:undefinedvoid可以接受的一种“空”。

  1. 以下写法符合规范
function logMessage(msg:string):void{
    console.log(msg)
}

function logMessage(msg:string):void{
    console.log(msg)
    return;
}

function logMessage(msg:string):void{
    console.log(msg)
    return undefined
}
  1. 那限制函数返回值时,是不是undefinedvoid就没区别呢?—有区别。因为返回值类型为void的函数,调用者不应依赖其返回值进行任何操作!对比下面两段代码:
function logMessage(msg:string):void{
	console.log(msg)
}

let result = logMessage('你好')

if(result){//此行报错:无法测试"void"类型的表达式的真实性
	console. log('logMessage有返回值')
}
function logMessage(msg:string):undefined{
	console.log(msg)
}

let result = logMessage('你好')

if(result){//此行无警告
	console. log('logMessage有返回值')
}

5.object

实际开发中用的相对较少,因为范围太大了。

object:所有非原始类型,可存储:对象、函数、数组等。

Object:所有可以调用Object方法的类型。除了undefinednull的任何值。

声明对象类型

  1. 限制一般对象可以使用下面形式
//限制person1对象必须有name属性,age为可选属性,可有可无
let personl: { name: string, age?: number }

//含义同上,也能用分号做分隔
let person2: { name: string; age?: number }

//含义同上,也能用换行做分隔
let person3:{
	name: string
	age?:number
}
//如下赋值均可以
person1={name:'李四',age:18}
person2={name:'张三'}
person3={name:'王五'}
  1. 索引签名:允许定义对象可以具有任意数量的属性,这些属性的键和类型是可变的,常用于:描述类型不确定的属性,(具有动态属性的对象)。
//限制person对象必须有name属性,可选age属性但值必须是数字,同时可以有任意数量、任意类型的其他属性
let person: {
	name: string
	age?:number
	[key:string]:any//索引签名,完全可以不用key这个单词,换成其他的也可以,保证key的类型是string,其值是any类型
    
//赋值合法
person = {
	name:'张三',
	age:18,
	gender:'男',
    city:'成都'
}

声明函数类型

//对函数接受的参数进行限制,对函数返回值进行限制
let count: (a: number, b: number) => number

count = function (x, y) {
	return x + y
}

//箭头函数,js中的写法
count=(x,y)=>{
    return x+y
}

备注:
TypeScript中的=>在函数类型声明时表示函数类型,描述其参数类型和返回类型。
JavaScript中的=>是一种定义函数的语法,是具体的函数实现。
函数类型声明还可以使用:接口、自定义类型等方式。

声明数组类型

let arr1:string[]
let arr2:Array<string>//泛型
   
arr1=['a','b','c']
arr2=['hello','world']

6.tuple

元组(Tuple)是一种特殊的数组类型,可以存储固定数量的元素,并且每个元素的类型是已知的且可以不同。元组用于精确描述一组值的类型,?表示可选元素。

let arr1:[string,number]
arr1=['hello',1]

let arr2:[string,boolean?]
arr2=['hello']

let arr3:[number,...string[]]//任意多个string类型
arr3=[100,'a','b']

7.enum

枚举(enum)可以定义一组命名常量,它能增强代码的可读性,也让代码更好维护。

  1. 数字枚举一种最常见的枚举类型,其成员的值会自动递增,且数字枚举还具备反向映射的特点,在下面代码的打印中,不难发现:可以通过值来获取对应的枚举成员名称。
//定义一个描述【上下左右】方向的枚举Direction
enum Direction {
	Up,
	Down,
    Left,
	Right
}

console.log(Direction)//打印Direction会看到如下内容
/*
	O:'Up',
	1:'Down',
	2:'Left',
	3:'Right',
	Up:0,
	Down:1,
	Left:2,
	Right:3
*/
            
//反向映射
console.log(Direction.Up)
console.log(Direction[0])

//此行代码报错,枚举中的属性是只读的
Direction.Up = 'shang'

指定枚举成员的初始值,后面成员从初始值自增

enum Direction {
	Up = 6,
	Down,
	Left,
	Right
}

console.log(Direction.Up); //输出:6
console.log(Direction.Down); // 输出:7
  1. 字符串枚举
enum Direction {
	Up="up",
	Down = "down",
	Left = "left",
	Right = "right"
}

let dir: Direction = Direction.Up;
console.log(dir);// 输出:"up"
  1. 常量枚举

官方描述:常量枚举是一种特殊枚举类型,它使用const关键字定义,在编译时会被内联,避免生成一些额外的代码。

编译时内联:所谓“内联”其实就是TypeScript在编译时,会将枚举成员引用替换为它们的实际值,而不是生成额外的枚举对象。这可以减少生成的JavaScript代码量,并提高运行时性能。

普通枚举:

enum Directions {
	Up,
	Down,
	Left,
	Right
}

let x = Directions.Up;

编译生成js

"use strict";
var Directions;
(function (Directions) {
	Directions[Directions["Up"] = 0O] = "Up";
	Directions[Directions["Down"] = 1] = "Down";
	Directions[Directions["Left"] = 2] = "Left";
	Directions[Directions["Right"] = 3] = "Right";
})(Directions |I (Directions = {}));

let x = Directions.Up;

常量枚举

enum Directions {
	Up,
	Down,
	Left,
	Right
}

let x = Directions.Up;

编译生成js

"use strict";
 let x = 0 /* Directions.Up */;

8.type

type可以为任意类型创建别名,让代码更简洁、可读性更强,同时能更方便地进行类型复用和扩展。

  1. 基本用法
type num=number

let price:num
price=100
  1. 联合类型
type Status=number|string

function printStatus(data:Status):void{
    console.log(data)
}

printStatus(404)
printStatus('404')


type Gender='男'|'女‘
function logGender(str:Gender){
	console.log(str)
}
logGender('男')
logGender('女')
  1. 交叉类型
//面积
type Area = {
	height:number;//高
    width:number;//宽
};

//地址
type Address = {
	num:number;//楼号
	cell:number; //单元号
	room:string;//房间号
}

//定义类型House,且House是Area和Address组成的交叉类型
type House = Area & Address;//包含Area和Address的所有属性
const house: House = {
	height:180,
	width:75,
	num:6,
	cell: 3,
	room:'702'
};

9.特殊情况

  1. 正常情况

在函数定义时,限制函数返回值为void,那么函数的返回值就必须是空。

function demo():void{
	//返回undefined合法
	return undefined
    
	//以下返回均不合法
	return 100
	return false
	return null
	return []
}
demo()
  1. 特殊情况
//自定义一个LogFunc类型,它的类型是函数,返回值为void
type LogFunc = () => void

//报错,此时LogFunc为类型,类似于number=9
LogFunc=function(){
}

const f1: LogFunc = () => {
	return 100;//允许返回非空值
}

const f2:LogFunc= ()=>200; // 允许返回非空值

const f3: LogFunc = function(){
    return 300;//允许返回非空值
}

10.类相关知识

class Person {
	//属性声明
	name: string
	age: number
    
	//构造器,必须写类型
	constructor(name: string, age: number){
		this.name = name
		this.age = age
    }
	//方法
	speak() {
		console.log('我叫:${this.name},今年${this.age}岁')
    }
}

//Person实例
const p1=new Person('周杰伦',38)

//继承
class Student extends Person{
    grade:string
    constructor(name:string,age:number,grade:string){
        super(name,age)
        this.grade=grade
	}
    study(){
        console.log('${this.name}正在学习中。。。。。')
    }
    
    //重写父类方法   1.与父类相同的名字  2.在函数前加override
    override speak(){
        console.log('我是学生,我叫:${this.name},今年${this.age}岁')
	}
}

const s1=new Student('许同学',16,'一年级')
s1.study()

11.属性修饰符

5

属性简写形式

简写前

class Person {
	public name: string;
	public age: number;
	constructor(name: string, age: number){
		this.name = name;
		this.age = age;
    }
}

简写后

class Person {
	constructor(public name: string,public age: number){}
}

12.抽象类

抽象类是一种无法被实例化的类,专门用来定义类的结构和行为,类中可以写抽象方法,也可以写具体实现。抽象类主要用来为其派生类提供一个基础结构,要求其派生类必须实现其中所有的抽象方法。抽象类不能实例化,其意义是可以被继承,抽象类里可以有普通方法、也可以有抽象方法

abstract class Package {
	constructor(public weight: number){}
	
    //抽象方法:用来计算运费,不同类型包裹有不同的计算方式
	abstract calculate(): number
    //abstract calculate(x:string,y:string): number
	
    //具体方法:打印包裹详情
	printPackage(){
		console.log('包裹重量为:${this.weight}kg,运费为:${this.calculate()}元');
    }
}

//标准包裹
class StandardPackage extends Package{
	constructor(weight:number,
	public unitPrice:number //每公斤的固定费率,简写形式
	){super(weight)}
	
    //实现抽象方法:计算运费
	calculate(): number {
		return this.weight * this.unitPrice;
    }
}

//创建标准包裹实例
const s1 = new StandardPackage(10,5)
s1.printPackage()


//特快包裹
class ExpressPackage extends Package {
	constructor(
		weight:number,
		private unitPrice:number,//每公斤的固定费率(快速包裹更高)
		private additional:number // 超出1okg以后的附加费
	){ super(weight)}
    
	//实现抽象方法:计算运费
	calculate(): number {
		if(this.weight > 10){
			//超出10kg的部分,每公斤多收additional对应的价格
			return 10 * this.unitPrice + (this.weight - 10) * this.additional
		}else {
            return this.weight * this.unitPrice;
        }
    }
 }

//创建特快包裹实例
const e1 = new ExpressPackage(13,8,2)
el.printPackage()

总结:何时使用抽象类?

  • 定义通用接口:为一组相关的类定义通用的行为(方法或属性)时。
  • 提供基础实现:在抽象类中提供某些方法或为其提供基础实现,这样派生类就可以继承这些实现。
  • 确保关键实现:强制派生类实现一些关键行为。
  • 共享代码和逻辑:当多个类需要共享部分代码时,抽象类可以避免代码重复。

13.interface(接口)

interface是一种定义结构的方式,主要作用是为:类、对象、函数等规定一种契约,这样可以确保代码的一致性和类型安全,但要注意interface只能定义格式,不能包含任何实现!

  1. 定义类结构
//定义接口
interface PersonInterface {
	name: string
	age:number
	speak(n: number): void
}

//定义一个类 Person,实现PersonInterface接口
class Person implements PersonInterface {
	constructor(
		public name: string,
		public age: number
	){}
    
	//实现接口中的speak方法
	speak(n: number): void {
		for (let i = 0; i< n; i++) {
			//打印出包含名字和年龄的问候语句
			console.log('你好,我叫${this.name},我的年龄是${this.age}');
        }
    }
}

//创建一个Person类的实例p1,传入名字'tom'和年龄18
const p1 = new Person('tom', 18);
pl.speak(3)
  1. 定义对象结构
interface UserInterface {
	name:string
	readonly gender:string //只读属性
	age?:number// 可选属性
	run: (n: number) => void
}

const user: UserInterface = {
	name:"张三",
	gender:'男',
	age:18,
	run(n) {
		console.log('奔跑了${n}米')
}
  1. 定义函数结构
interface CountInterface {
	(a: number,b: number):number;
}
const count: CountInterface = (x, y) => {
	return x + y
}
  1. 接口之间的继承
interface PersonInterface {
	name:string //姓名
	age:number // 年龄
}

//继承的接口
interface StudentInterface extends PersonInterface {
	grade:string //年级
}

const stu: StudentInterface = {
	name:'张三',
	age:25,
	grade:'高三'
}
  1. 接口的自动合并
// PersonInterface接口
interface PersonInterface {
	//属性声明
	name: string
	age:number
}

//给PersonInterface接口添加新属性
interface PersonInterface {
	//方法声明
	speak(): void
}

// Person类实现PersonInterface
class Person implements PersonInterface {
	name:string
	age:number
	//构造器
	constructor(name: string, age: number) {
		this.name = name
		this.age = age
    }
	//方法
	speak() {
		console.log('你好!我是老师:',this.name)
    }
}

总结:何时使用接口?

  • 定义对象的格式:描述数据模型、AP响应格式、配置对象....等等,是开发中用的最至的场景。
  • 类的契约:规定一个类需要实现哪些属性和方法。
  • 扩展已有接口:一般用于扩展第三方库的类型,这种特性在大型项目中可能会用到。

一些相似的概念的区别

1.interface与type

相同点

interface和type都可以用于定义对象结构,在定义对象结构时两者可以互换。

//使用 interface 定义 Person 对象
interface PersonInterface {
	name:string;
	age:number;
	speak(): void;
}

// 使用type 定义 Person 对象
type PersonType ={
	name: string;
	age:number;
	speak(): void;
}
// 使用PersonInterface
let person: PersonInterface ={
	name:'张三’,
	age:18,
	speak(){
		console.log('我叫:${this.name},年龄:${this.age}')
    }
}


//使用PersonType
let person: PersonType = {
	name:'张三',
	age:18,
	speak(){
		console.log('我叫:${this.name},年龄:${this.age}')
    }
}

不同点

interface:更专注于定义对象和类的结构,支持继承、合并。
type:可以定义类型别名、联合类型、交叉类型,但不支持继承和自动合并。

接口的继承与合并

interface PersonInterface {
	name:string //姓名
	age:number//年龄
}

//利用接口的自动合并
interface PersonInterface {
	speak:()=>void
}
//利用接口之间的继承
interface StudentInterface extends PersonInterface {
	grade:string //年级
}

const student: StudentInterface = {
	name:'李四',
	age:18,
	grade:'高二'
	speak() {
		console.log(this.name,this.age,this.grade)
    }
}

type的交叉类型

//使用type定义Person类型,并通过交叉类型实现属性的合并
type PersonType = {
	name:string;//姓名
	age:number;//年龄
}&{
	speak: () => void;
};

//使用type定义Student类型,并通过交叉类型继承PersonType
type StudentType = PersonType &{
	grade:string;//年级
}

const student: StudentType = {
	name:'李四',
	age:18,
	grade:'高二',
	speak() {
		console.log(this.name, this.age, this.grade);
};

2.interface与抽象类

相同点:都能定义一个类的格式(定义类应遵循的契约)
不相同:接口:只能描述结构,不能有任何实现代码,一个类可以实现多个接口。
抽象类:既可以包含抽象方法,也可以包含具体方法,一个类只能继承一个抽象类。

泛型

泛型允许我们在定义函数、类或接口时,使用类型参数来表示未指定的类型,这些参数在具体
使用时,才被指定具体的类型
,泛型能让同一段代码适用于多种类型,同时仍然保持类型的安
全性。

如下代码中 就是泛型,(不⼀定⾮叫 T ),设置泛型后即可在函数中使⽤ T 来表示

  1. 泛型函数
function logData<T>(data: T): T{
	console.log(data)
	return data
}

logData<number>(100)
logData<string>('hello')
  1. 多个泛型
function logData<T, U>(datal: T, data2: U): T | U{
	console.log(datal,data2)
	return Date.now()%2? datal : data2
}

logData<number, string>(100, 'hello')
logData<string, boolean>('ok', false)
  1. 泛型接口
interface PersonInterface<T> {
	name:string,
	age:number,
	extraInfo: T//额外信息
}

let pl: PersonInterface<string>
let p2: PersonInterface<number>
    
pl={name:'张三',age:18,extraInfo:'一个好人'}
p2={ name:'李四',age:18,extraInfo:250}
  1. 泛型类
class Person<T> {
	constructor(
		public name: string,
		public age: number,
		public extraInfo:T
     ){}
	speak(){
		console.log('我叫${this.name}今年${this.age}岁了')
		console.log(this.extraInfo)
    }
}
const p1 = new Person<number>("tom", 30, 250);

类型声明文件

类型声明文件是TypeScript中的一种特殊文件,通常以·d.ts作为扩展名。它的主要作用是为现有的JavaScript代码提供类型信息,使得TypeScript能够在使用这些JavaScript库或模块时进行类型检查和提示。

export function add(a, b) {
	return a + b;
}

export function mul(a, b) {
	return a * b;
}
declare function add(a: number, b: number): number;
declare function mul(a: number, b: number): number;
export { add, mul };
// example.ts
import { add, mul } from "./demo.js";
const x = add(2, 3); // x 类型为 number
consty = mul(4, 5); // y 类型为 number
console.log(x,y)
posted @ 2025-03-29 11:55  狐狸胡兔  阅读(53)  评论(0)    收藏  举报