当前位置: 首页 > news >正文

前端TS基础

文章目录

  • 一、类型
    • 1、定义类型
    • 2、any、unknown、never
    • 3、基础类型
    • 4、联合类型
    • 5、交叉类型
    • 6、type、typeof
    • 7、作用域
  • 二、数据结构
    • 1、数组
    • 2、元组
    • 3、函数类型
    • 4、对象类型
  • 三、接口
  • 四、泛型
  • 五、enum
  • 六、断言
  • 七、工具
    • 1、模块
    • 2、namespace
    • 3、装饰器
    • 4、declare
    • 5、运算符
    • 6、映射类型
    • 7、类型工具
    • 8、语法注释
    • 9、tsconfig.json

TypeScript 可以看成是 JavaScript 的超集(superset),即它继承了后者的全部语法,添加了一个独立的类型系统

一、类型

1、定义类型

  • js的类型是动态的,变量定义以后,可以赋值另一个类型的值,这导致了不确定性;
// 报错
// 不能将类型“number”分配给类型“string”。
let bar:string = 123;// 类型推断为string; 鼠标放在sayHello函数上,查看函数定义,可以看到
// 返回值类型被推断; 
// (local function) sayHello(name: string | number): string
function sayHello(name:string | number){return name + "";
}
sayHello('zhangsan')

2、any、unknown、never

// any类型
// 加了any类型,感觉是回到了js,当然一般的项目会限制使用any类型
let anyVar: any = 123;
let anyVarUndefined: any;anyVar = "hello world";
let anyVarbar = anyVar;
console.log(anyVar); // 输出hello world
console.log(anyVarUndefined); //不会报错,any类型可以赋值undefined
console.log(anyVarbar + 123); // any类型变量赋值给其他变量,会导致其他变量也变成any类型// 不给变量定义类型,那么等于any类型
// (local function) getNumber(count1: any, count2: any): any
function getNumber(count1, count2){return count1 + count2;
}
// unknown
// 类型感觉只是对值的类型规定,而不能再后续正常使用
let num: unknown = 1;
num = num + 1; // 报错:“num”的类型为“未知”。
// 在判断中限制unknown的类型为具体类型,就可以使用了
if(typeof num === 'number'){num = num + 1
}
// never类型
let neverVar: never;
// 空类型,不能在任何地方使用
neverVar = neverVar + 1; // 报错:不能将类型“number”分配给类型“never”。
// 一般用于函数永不返回的情况,比如抛出异常
function f(): never {throw new Error('Error');// 注意当你返回值类型为never,依旧return语句会报错// 需要使用as 类型推定return undefined as never;
}
// never 是其他类型子集,所以可以赋值给其他类型
// never是底层类型,在这之上可以再次定义类型
let v1:number = f(); // 不报错
let v2:string = f(); // 不报错

3、基础类型

// 基础类型
// string\number\boolean\null\undefined\symbol
let str:string = "hello world";
let num1:number = 123;
let bool:boolean = true;
let nullVar:null = null;
let undefinedVar:undefined = undefined;
let symbolVar:symbol = Symbol();// 对象类型
const x:object = { foo: 123 };
const y:object = [1, 2, 3];
const z:object = (n:number) => n + 1;// 包装类型
// 大写String包含两种:一个是字面量类型,一个是对象类型;
// 小写string只有字面量类型
const s1:String = 'hello'; // 正确
const s2:String = new String('hello'); // 正确
const s3:string = 'hello'; // 正确
const s4:string = new String('hello'); // 错误,不能将类型“String”分配给类型“string”。// 大写Object,除了null和undefined外,Object包含其他所有类型
let obj:Object;
obj = true;
obj = 'hi';
// 小写object只有引用数据类型
let obj1:object;
obj1 = [];// 值类型
// ts中任何变量都是有类型的,注意很多时候被默认推导了
// let 会给 strValue1 推导类型为 string
let strValue1 = 'hello';
// const 会给 strValue2 推导类型为 hello (普通类型的值)
const strValue2 = 'hello';
// const 会给 objValue 推导类型为 object (引用数据的值)
const objValue: object = { foo: 1 };
// 注意:引用数据会被推导
//   const objValueNoType: {
//     foo: number;
// }
const objValueNoType = { foo: 1 };// 主动设置值类型(单个值)
let numValue1: 1 = 123; // 不能将类型“123”分配给类型“1”。
let numValue2: 123 = 123; // 不能将类型“123”分配给类型“1”。
let numValue3: number = 123;
// 注意 number 类型 包含 123 类型
numValue2 = numValue3; // 错误:不能将类型“number”分配给类型“123”。
numValue3 = numValue2; // 正确

4、联合类型

// 联合类型
// 多个类型组合在一起的类型,可以是不同类型的值,也可以是同一类型的值
// 可以给变量增加类型 null | undefined
let unionValue1: string | number | null | undefined = 123;
let unionValue2: 'hello' | 'world' | number = 'hello';
// 联合类型可以被看成是 类型范围的扩大
// 使用的时候需要类型缩小,否则会报错;也就是说类型范围的变化不会减少工作量
if(typeof unionValue1 === 'number'){console.log(unionValue1.toFixed(2));
}

5、交叉类型

// 交叉类型
// let intersectionValue1: number | "hello"
// string类型包含hello类型,交叉类型就是'hello'类型
// 最终交叉类型依旧是联合类型:number | "hello"
let intersectionValue1: (string | number) & (number | boolean | 'hello') = 'hello';

6、type、typeof

// type 类型别名
// 给一个类型起一个别名,方便使用;类型可以是一个变量
// ts增加了类型系统,那么需要搭配类型变量,更加灵活使用
type MyType = string | number | boolean;
let myVar: MyType = true;// typeof
// typeof 在js里返回最终值的类型
// typeof 在ts里获取类型,两者是不一样的
console.log('typeof myVar', typeof myVar); // boolean js中的 typeof 运算符
let myTypeofVar1: MyType;
// 使用其他变量的类型
// let myTypeofVar2: MyType
let myTypeofVar2: typeof myTypeofVar1 = true;

7、作用域

// 类型变量具有作用域
try {type MyType = string | number;
} catch (error) {type MyType = boolean;
}

二、数据结构

1、数组

// 数组类型
// 规定了数组中每个元素的类型,但不规定元素的个数
// 成员数组类型
// number[] 等价于 (number)[]
let arr0: number[] = [1, 2, 3];
let arr1: (string | number)[] = [1, 2, '3'];
// 泛型数组类型
let arr2: Array<string | number> = [1, 2, '3'];// 获取数组类型其中的一个元素类型
type Names = (string | number)[];
type Name = Names[0]; // string | number
type Name1 = typeof arr1[0]; // string | number
// 注意类型数据不能打印出来,只能在编译期间使用
// console.log('数组类型', Name); // 报错// 数组类型推断
// 自动推断为:let arr3: (string | number)[] (前面讲过,默认是any类型)
let arr3 = [1, 2, '3'];
// arr3.push(true); // 推断过一次,不会继续推断;类型不对会报错// 只读数组
// 数组的元素不能被修改,只能读取
let readonlyArr1: readonly string[] = ['hello', 'world'];// readonly string[] 相当于简化版,没有push、pop等属性
// 所以readonly string[] 是父类型,string[]是他的子类型,子类型添加了更多方法
arr3 = readonlyArr1; // 错误:父类型不能赋值给子类型
readonlyArr1 = ['hello', 'world']; // 正确
// 简单说,属性多\功能全的类型可以赋值给属性少的类型(如果他们有父子关系),但是反过来不行// 另外三种只读数组
// ReadonlyArray\Readonly\const
const a1:ReadonlyArray<number> = [0, 1];const a2:Readonly<number[]> = [0, 1];const arr = [0, 1] as const;// 多维度数组;
// 从左往右读取,最左边是数组最深层的元素,最右边是数组最外层的元素
const arr4: string[][] = [['hello', 'world'], ['foo', 'bar']];

2、元组

// 元组类型
// 规定了数组中每个元素的类型,且元素的个数也做规定;可选元素可以用?表示,只能放在最后面
let tuple1: [string, number?] = ['hello', 123];
// ... 扩展运算符可以增加无限多个元素
let tuple2: [string, ...number[],] = ['hello'];
// 元组中元素的名称, 没有实际意义,只是语义化的作用
let tuple3: [message: string, count: number] = ['hello', 123];
// 获取元组类型的元素类型,通过数字索引
type TupleType = [string, number?];
// 注意类型变量也只能赋值给类型变量;不能当成值变量使用
type TupleType1 = TupleType[1]; // number | undefined
// const tuple4 = TupleType[0]; // 报错// 只读元组
// readonly 关键词;或者使用泛型 Readonly<[string, number]>
let readonlyTuple1: readonly [string, number] = ['hello', 123];
let readonlyTuple2: Readonly<[string, number]>  = ['hello', 123];// 元组长度length
let tupleLength1: [string, number] = ['hello', 123];
let tupleLength2: [string, number, boolean?] = ['hello', 123, true];
let tupleLength3: [string, ...number[], ] = ['hello', 123, ];
// 当元组长度固定,length属性为定值,使用其他值会报错
// if(tupleLength1.length === 3){ // 报错
//     console.log('tupleLength1.length', tupleLength1.length);
// }
// 当元组长度固定几个选项 1、2、3
if(tupleLength2.length === 3){console.log('tupleLength2.length', tupleLength2.length);
}
// 当元组长度不固定,可以随意判断长度
if(tupleLength3.length === 3){console.log('tupleLength2.length', tupleLength3.length);
}// 元组在函数参数中使用
// 注意函数参数一般有固定的元素数量,这个时候使用元组确定数量
function tupleSayHello(name:string, age:number):void{console.log(`hello ${name}, your age is ${age}`);
}
const tupleArr1: [string, number] = ['hello', 123];
const tupleArr2 = ['hello', 123]; // (string | number)[] 会被认为数量无限
tupleSayHello(...tupleArr1); // 正确
// sayHello(...tupleArr2); // 报错 sayHello只接受有限的2个参数const tupleArr3 = ['hello', 123] as [string, number]; // 推断类型
// 只读的值数组,可以用as const来定义成元组类型
const tupleArr4 = ['hello', 123] as const;
tupleSayHello(...tupleArr4)

3、函数类型

// 函数类型
// 默认是有返回值类型推断的,可以省略(除非条件不充足,无法推断)
type funType = (x: number, y: number) => void;
// 方式1;注意不写参数类型会被推断为any类型
const funAdd1 = (x: number, y: number, z) => x + y;
// 方式2
const funAdd2: (x: number, y: number) => number = (x, y) => x + y;// 参数数量
let funAdd3: (x: number, y: number) => number = (x, y) => x + y;
funAdd3 = (x: number) => x + 1; // 正确;可以少于初始化定义的参数数量
// funAdd3 = (x: number, y: number, z: number) => x + y + z; // 错误:参数大于定义的数量// keyof 关键字获取函数的类型(注意得到的是type名)
const funAdd4: funType = (x: number, y: number) => x + y; // 正确
// keyof 关键字获取函数的类型(注意得到的是类型)
// const funAdd4 = (x: number, y: number) => x + y; // 正确
const funAdd5: typeof funAdd4 = (x, y) => x + y; // 正确;// 对象方式定义函数类型
let fooObj: {(x:number): void;
} = (x) => {return x + 1;
};
// 等同于
interface FooObj {(x:number): void;
}
let fooObj1: FooObj = (x) => {return x + 1;
};// 特殊类型 Function
let fooObj2 = (cb: Function, x: number) => {return cb(x + 1);
};// 箭头函数; 注意ts中参数区域要用括号包裹起来;返回值写在括号后面
const funAdd6 = (x: number): number => x;// 参数可选; 注意 y的类型是 number | undefined
// 可选的?的位置只能在最后面追加参数;前面的参数想要使用undefined得单独加
// void 返回值表示不能使用 return 返回内容
const funAdd7 = (x: number | undefined = 0, y?: number): number => {// 注意在代码中写的typeof是值的类型判断,而不是类型变量if(typeof x === 'number' &&  y !== undefined){return x + y;}x?.toFixed(2); // 注意?.运算符,可以安全的使用undefinedy?.toFixed(2);// 如果不判断就使用x、y,会报错// return x + y// 注意必须有默认值,因为定义了返回值return 0;
};
funAdd7(undefined); // 正确
funAdd7(1); // 正确
funAdd7(1, undefined); // 正确
funAdd7(1, 2); // 正确
funAdd7(undefined, 2); // 正确// 函数参数默认值
// 不可以可选时使用默认值:y?: number = 0
const funAdd8 = (x: number = 0, y: number = 0) => x + y;
// undefined 不会覆盖默认值
funAdd8(undefined); // 0// 参数结构
type FunTypeAdd9 = {x: number, y: number}
const funAdd9 = ({ x, y }: FunTypeAdd9) => x + y;
funAdd9({ x: 1, y: 2 }); // 3// rest参数
// 剩余参数,可以接收任意数量的参数,会被存入一个数组中
// args 这个名字可以自定义, 但是必须放在最后面
const funAdd10 = (type: string, ...args: number[]) => {let sum = 0;for(let i = 0; i < args.length; i++){sum += args[i];}return sum;
};
funAdd10('add', 1, 2, 3); // 6// readonly 关键字
// const funAdd11 = (x: readonly number[], y: number) => x[0]++;
// funAdd11( [1, 2, 3], 1); // 错误:不能修改只读数组// void 关键字
// 一般用于函数没有返回值,或者返回值没有意义的情况
const funAdd12 = (x: number): void => {// 没有return,或者return undefined || null// 或者 throw new Error('something wrong');// 当然函数默认返回的就是undefined// return 1; // 错误// return ''; // 错误return; // 正确return undefined; // 正确
};
funAdd12(1); // 正确// 函数重载
// 注意不能写const let定义,使用function定义
// 同样不能写箭头函数了
// 当你传入两种模式,代码层面做好判断即可;不同的参数返回不同的数据类型
function funAdd13 (x: number): number;
function funAdd13 (x: string): string;
function funAdd13 (x: number | string): number | string {// number => numberif(typeof x === 'number'){return x + 1;}// string => stringreturn x + '1';
};
funAdd13(1); // 2
funAdd13('hello'); // hello// 构造函数
// 函数默认是不能当成构造函数使用的
// const funAdd13_child = new funAdd13('hello'); // 报错// type 构造函数, new 关键字 开头
type FunAdd14_new = new (x: number) => object;type funAdd_type = {new (x: number): object;
}
// funAdd_type 只能和 Class 结合使用
class FunAdd14_class {constructor(public x: number) { this.x = x + 1;}
}
const funAdd14: funAdd_type = FunAdd14_class;
const funAdd14_child = new funAdd14(123); // 正确

4、对象类型

// 对象类型
// 字面量对象,注意可以使用, 或者;
// 属性个数固定,必须包含所有属性(有点类似于元组强制数量)
const objValue1: {name: string,age: number,sayHello: () => void; // 函数方式 1sayHello2(): void; // 函数方式 2count?: number // 可选属性
} = {name: 'vbj',age: 18,sayHello: () => {console.log(`hello ${this.name}`);}
};
console.log(`objValue1`, objValue1);
// 删除必选属性,不再被允许
// delete objValue1.name; // 错误
// 删除可选属性,可以被删除
delete objValue1.count; // 正确// type 定义对象类型
type ObjValue2 = {age: number[],name?: string,
}
// 获取某一个元素的类型;注意类型变量不是纯对象,不能使用 ObjValue2.name
type ObjValue2Name = ObjValue2['name']; // string// interface 定义对象类型
interface ObjValue3 {toString(): string;name: string;age?: number;
}
// 如果属性是构造函数自带的,可以省略(如 toString)
// 因为对象默认自带 toString 方法(Object.prototype.toString)
const objValue3: ObjValue3 = {name: 'vbj',age: 18,
};
// const objValue3Age = objValue3.age * 1; // 错误:不能使用 undefined 类型
if (objValue3.age) { // 正确; 可选值需要经过判断再使用;有点类似函数参数的可选const objValue3Age = objValue3.age * 1; // 正确
}// age1、age2这两个是不一样的
// 前面必须定义属性age1;age2可以有可以没有,只不过他们的值类型相似
type ObjValue4 = {age1: number | undefined,age2?: number,
}// readonly 关键字
type ObjValue5 = {readonly name: string,readonly age: number,readonly points: number[];readonly count: {count1: number,count2: number,}
}
const objValue4: ObjValue5 = {name: 'vbj',age: 18,points: [1, 2, 3],count: {count1: 100,count2: 200,}
};
// 浅层修改属性报错
// objValue4.name = 'hello'; // 错误// 深层属性修改; 正确
objValue4.points[0] = 100; // 正确
objValue4.count.count1 = 100; // 正确// 引用数据会突破readonly限制
// 内存数据优先于关键字
const objValue5 = {name: 'vbj',age: 18,points: [1, 2, 3],count: {count1: 100,count2: 200,}
}const objValue6:ObjValue5 = objValue5
objValue5.name = 'hello'; // 正确
console.log('objValue6', objValue6.name); // hello// 属性名索引(索引也具有类型)
// 注意索引类型只能写一个;比如 propName: string只能写一个type ObjValue7 = {[propName: number]: number,// [propName: string]: string, // 报错。索引代表的值类型冲突// string索引优先级更高,只要他的容错度高就可以[propName: string]: string | number,// [propName: string]: string | number | undefined,// 索引类型和普通类型,很容易冲突// name: boolean // 错误:[propName: string] 和 boolean 类型冲突
}// 解构赋值
// 注意单独的变量不能使用类型注解;只能集体使用;因为:号会被识别成变量别名
const { name: vbjName, age, points, count }: {name: string,age: number,
} = {name: 'vbj',age: 18,
}// 结构类型; 父类型,基础;子类型比父类性更加严格(包含父类型的属性)
const objPointA = {x: 1,y: 1
};const objPointB:{ x: number } = objPointA; // 正确for (const key in Object.keys(objPointB)) {// 报错;objPointB的值中可能出现除x以外的属性,默认为any// const item = objPointB[key];// 所以只能使用objPointB中确定的属性const item = objPointB.x;
}// 字面量和变量区别
function sayHelloObj({name: string}): void {}
const sayHelloObjParam = {name: 'vbj', age: 18};
sayHelloObj(sayHelloObjParam); // 正确;结构类型满足即可(参数可多不能少)
sayHelloObj({name: 123, age: 18}); // 错误:age类型不匹配; 字面量会匹配参数数量// 空对象
// 写空对象,会认为后续无法添加属性
const emptyObj: {} = {}; // 类型被锁定 const emptyObj: {}
// emptyObj.name = 'vbj'; // 报错const emptyObj2: Object = { name: 'vbj' };
emptyObj2.name = 'vbj'; // 报错// 初始化对象
// useState后的泛型区域内就是 countObject的类型;如果默认空对象,要给每个属性写可选类型
// const [countObject, setCountObject] = 
// useState<{ count?: number, age?: number }>({}); // 方式 1
// 或者给默认值
const defaultCountObject = { count: 0, age: 0 };
const [countObject, setCountObject] = 
useState<{ count: number, age: number }>(defaultCountObject);  // 方式 2
const countObjectValue = countObject?.count;
useEffect(() => {setCountObject({ count: 0, age: 18 }); // useState类型
}, []);

三、接口

// interface基础用法
interface Person {firstName?: string;lastName?: string; // 可选属性readonly age?: number; // 只读属性[key: string]: any; // 注意每一种key类型,只能有一种值类型[key: number]: string; // key number索引
}
const persons: Person = {firstName: 'John',lastName: 'Doe',age: 30,
};
// interface的数字索引可以定义数组
const personKeys: Person = ['firstName', 'lastName', 'age'];// interface的函数
interface Person2 {// interface 函数重载;注意只能写function,不能写箭头函数fun(name: string): string;// fun(name: number): number;fun1?: (age: number) => number;fun2?: { (name: string): void };
}
// 具体的重载,只能在具体函数体使用,interface重载只是定义
const person2: Person2 = {fun: function (name: string): string {return `hello ${name}`;},
};// 独立函数; (type可以更方便完成)
interface Person3 {(name: string, age: number): void;
}
const person3: Person3 = function (name: string, age: number): void {console.log(`hello ${name}, your age is ${age}`);
};
// 构造函数
interface Person4 {new (name: string, age: number): void;
}
class person4Class {name: any;age: any;constructor(name: any, age: any) {this.name = name;this.age = age;}
}
// 注意这里的Person4是接口,person4Class是类
const person4: Person4 = person4Class;// 继承
interface Animal {name: string;
}
interface AnimalColor {color: string;
}
// 当type是对象时,可以被继承
type AnimalType = {type: string;
};
// 继承Animal,AnimalColor; 注意属性不能重重复,否则报类型不兼容
interface Dog extends Animal, AnimalColor, AnimalType {bark(): void;// color: number; // 属性“color”的类型不兼容。
}
// 同名的interface会合并属性
// 当一个interface没有你想要的属性,又不想新增,可以直接合并
interface Dog {age: number; // 新增属性
}// type 和 interface 的区别
// 相同点
// 1. type都命名为对象的时候,基本一致
// 2. 可以定义属性类型// 不同点
// 1. interface 可以继承,type 不可以
// 2. interface 可以合并,type 不可以
// 3. interface 只能写对象,type 可以写任意类型(类型更灵活)
// 4. type 有联合类型、交叉类型,interface 没有
// 5. type 不能重复声明,interface 可以重复声明
// 6. interface 中使用 this 关键字,type 中不能使用// 个人总结
// 1. interface 用于组件参数列表,API接口参数定义,函数返回值,更多属于业务层面
// 2. type 用于复杂的类型定义,更多属于类型层面

四、泛型

// 泛型// 当参数和返回值有关系的时候,无法明显看出来关系// 即便是指定类型为一致,也只是表明他们类型恰好一致,而不是恒定一致性const getArrayFirst1 = (num: any[]): any => {return num[0];};// 写法 1 functionfunction getArrayFirst2<T>(num: T[]): T {return num[0];}// 写法 2 箭头函数// 注意 T后面有逗号const getArrayFirst3 = <T,>(num: T[]): T => {return num[0];};// 前面两种是根据值推到处类型,也可以主动设置类型// 写法 3 interfaceinterface GetArrayFirst4 {<T>(num: T[]): T;}const getArrayFirst5: GetArrayFirst4 = (num) => {return num[0];};// 泛型可以不写,默认根据实参推导getArrayFirst2([1, 2, "3"]); // <string | number>// 也可以指定类型;如果复杂的类型,尽可能主动传入泛型变量getArrayFirst2<string | number>([1, 2, "3"]);// interface + 泛型// interface 可以 动态设置类型interface GetArrayFirst6<T> {(num: T[]): T;}// 注意 interface有泛型时,必须使用,不能省略const getArrayFirst7: GetArrayFirst6<string | number> = (num) => {return num[0];};getArrayFirst7([1, 2, "3"]);// class + 泛型// 类也可以使用泛型class MyClassGetNum1<T> {// static num: T[] = []; // 报错;静态属性不能使用泛型;只能使用实例属性// constructor 相当于函数的参数入口constructor(public num: T[], ...args: any[]) {}getFirst(): T {return this.num[0];}}// T === string | number 默认根据实参推导const myClassNum1 = new MyClassGetNum1([1, 2, "3"]);// class 和构造函数的 关系// class 改造成 函数function MyClassGetNum1Func<U>(ClassCore: typeof MyClassGetNum1, num: U[], ...args: any[]): MyClassGetNum1<U> {return new ClassCore<U>(num, ...args);}// 注意 U 如果不传,会根据 存在的U推导;// 比如参数有U,传了参数但函数没有传U,会根据参数确定Uconst myClassNum2 = MyClassGetNum1Func(MyClassGetNum1, [1, 2, "3"]);console.log("myClassNum2", myClassNum2.getFirst());// type + 泛型type GetArrayFirst8<T> = (num: T[]) => T;const getArrayFirst9: GetArrayFirst8<string | number> = (num) => {return num[0];};getArrayFirst9([1, 2, "3"]);// 树形结构的 type type 可以使用自己type Tree<T> = {value: T;left?: Tree<T>;right?: Tree<T>;};const treeType: Tree<number> = {value: 1,left: {value: 2},right: {value: 9}};// 泛型默认值function getArrayFirst10<T = string>(num: T[]): T {return num[0];}// 函数没传泛型,根据参数推导,并且覆盖默认值getArrayFirst10([1, 2, "3"]);class MyClassGetNum2<T = string> {constructor(public num: T[]) {}// 可以设置在参数位置add(num: T): void {this.num.push(num);}}const myClassNum3 = new MyClassGetNum2([1, 2, "3"]);// 推导的泛型,会覆盖默认值// console.log("myClassNum3", myClassNum3.add(true)); // 报错// 数组泛型// Array 相当于一个 interfaceconst arrInterface1: Array<number> = [1, 2, 3];// 只读数组 ReadonlyArrayconst arrInterface2: ReadonlyArray<number> = [1, 2, 3];// arrInterface2.push(1); // 报错// arrInterface2 = []; // 报错// 泛型条件约束// 也就是说和默认类型不同,约束类型是不会被覆盖的,会和T一起构成联合类型// 简单说 A extends B 就是 A 必须是 B 的子类型;// A 范围小一些,B 范围大(条件宽松)// 注意 = 10 指的是T的默认值,不是stringfunction getArrayFirst11<T extends number | string = 10>(num: T[]): T {return num[0];}// 使用了 extends 约束,最好是主动传入泛型,而不是依赖默认推导getArrayFirst11<number | string>([1, 2, 3, 4, "5"]);// 1、泛型使用会增加复杂度,尽量不要滥用,超过 3 个重复的类型考虑使用泛型

五、enum

 // enum 枚举类型// 类似于js对象,编译后也是对象;enum这里的作用是提供 类型 + 枚举// 枚举值的特点是名称很重要(语义化),值可以变化程度大enum Color {// 枚举值可以不用从 0 开始,可以设置其他值Red,Yellow, // 默认自增 + 1Green = "Green",// 注意数字索引中断以后,不会默认自增,需要手动设置Blue = 0// obj = {//   name: "obj"// }}const color: Color = Color.Red;console.log("color", color);// 同名枚举值,会合并// 注意数字索引为0的位置,只有一个;其他的同名enum要手动设置enum Color {// Pink, // 0,但是报错,因为已经存在了Pink = "Pink"}// const enum// 编译后会直接替换成 值,不会生成对象; 提高了效率// 编译后// const color = 0;// 函数和 enum 类型// 当参数使用 enum,不能再传值,而是只能穿 enum 类型function getColor(color: Color): string {switch (color) {case Color.Red:return "红色";case Color.Yellow:return "黄色";default:return "未知";}}// console.log("getColor", getColor('Green')); // 报错,类型不匹配console.log("getColor", getColor(Color.Green)); // 正确// keyof 索引类型// 得到所有 key 的联合类型;typeof 是为了获取类型,keyof 获取 keytype Color_key = keyof typeof Color;// 获取了所有值 key 表示枚举的值type Color_value = { [key in Color]: any };// enum 反向映射// 枚举值可以反向映射到枚举名; 注意枚举值相同,反向映射得到最后一个// 注意使用[]反向映射也可以获取枚举值,获取枚举值尽量使用Color.Blue规范const color_reverse = Color[0]; // 0 映射到 Blue 而不是 Red// Color["123"] // 123 映射到 undefined// Color["Blue"] // Blue 枚举值 0// Color.Blue; // 0console.log("Color_key", color_reverse, );

六、断言

// 断言
type Person_As1 = {name: string;age: number;count: number;
}
const person_assert  = {name: 'vbj',
}
// 断言 即便不满足该类型,可以认为指定断言,这样可以绕过检查(可能导致异常)
const person_assert_type1: Person_As1 = person_assert as Person_As1;
// 当你定义数据初始化时,可能没有那么多数据,可以指定断言以后,逐步添加属性
person_assert_type1.age = 18;
console.log('person_assert_type1', person_assert_type1.count);// 使用断言的场景,很有可能你所使用的数据,是很模糊的
// 不确定有哪些属性,或者暂时没有; 这个时候很容易把父类性赋值给子类型
// 可以看到不满足条件也被定义了
const person_assert_type2: Person_As1 = {name: 'vbj',age: 18,count: 100,num: 100 
} as Person_As1// 断言条件
// 只要as右边是目标类型的子类型即可(子类型 = 父类性 + 额外属性)
// 比如 const value: T1 = valueDefault as T2;
// T2 必须是 T1 的子类型; 
// valueDefault是T2的子类型 或者 T2是valueDefault的子类型
const person_assert_type3: Person_As1 = {name: 'vbj',
} as { name: string, age: number, count: number, num: number }; // 正确// 最终把数字赋值给字符串
// 注意 any unknown 是所有类型的父类性
// const person_assert_type4: string = 100 as string; // 错误 as 两边的值类型不匹配
const person_assert_type4: string = 100 as unknown as string; // 正确 中转 unknown 类型// as const 关键字
// let const 关键词会导致变量的类型不一致(简单说const会让变量的类型固定)
// let string1: string
let string1 = 'JavaScript';
// const string2: "JavaScript"
const string2 = 'JavaScript';// let string3 = string1 as const; // 报错 as const 前面只能出现基本数据字面量,不能是变量
// let string3: "JavaScript"
let string3 = 'JavaScript' as const;// 对象字面量 + as const 关键字;
// 会导致对象属性变成只读readonly, 不能再添加属性; 
// 属性的值也被改成值类型,比如name类型不是string,而是'vbj'
const person_as_type5 = { name: 'vbj', } as const; // 正确,空对象类型
// person_as_type5.age = 1 // 错误,不能添加属性// 枚举值类型锁定
enum Person_enum1 {name,age = 'age',
}
let person_enum1 = Person_enum1.name;            // Person_enum1
let person_enum2 = Person_enum1.name as const;   // Person_enum1.name// 非空断言
function AsFun1(value: string | null): string {// 断言 value 非空,否则会报错; 这个例子中其实就是排除 null// 非空表示这里一定有值return value!.toUpperCase();
}// 断言函数(断言逻辑的复用)
// 这里断言只要是string类型,就抛出异常
// 注意 asserts value is string 只是语义化;具体逻辑需要自己设定
function isStringAs(value:unknown):asserts value is string {if (typeof value !== 'string')throw new Error('Not a string');
}
function AsFun2(value: string | number | null): string {isStringAs(value); // 调用断言函数// 如果断言函数使用得当,那么错误会出现在断言函数,不会在这里报错return value.toUpperCase();
}
AsFun2(null);

七、工具

1、模块

    // 模块// type 和 interface 区分// 类型定义文件:module_type.d.tsexport interface interfaceName {name: string;}export type typeName = {age: number;}export let num = 123;// 引入类型定义文件: const.ts// 方式 1; 单个确定为type类型import { type interfaceName, typeName } from './module_type';// 方式 2; 批量确定为type类型import type { interfaceName, typeName, num } from './module_type';const numCurrent = num; // 报错,num是类型,而不是值

2、namespace

    // namespace// 命名空间可以将类型定义文件拆分为多个文件,方便管理// 命名空间,可以导出和引入;// 如果未导出,外部无法访问;// 可以和函数重名,重名的时候,相当与给函数增加属性;function module_namespace1(){}namespace module_namespace1 {export interface interfaceName {name: string;}}// 同名的命名空间,会进行合并;// 注意,只会合并 export 的成员;namespace module_namespace1 {export let num = 123;let nullVar = null;}namespace module_namespace2 {import interfaceName = module_namespace1.interfaceName;import num = module_namespace1.num;// import nullVar = module_namespace1.nullVar; // 报错}

3、装饰器

    // 装饰器// 装饰器可以替换类中原有的方法、属性等function simpleDecorator() {console.log('hi');}function simpleDecoratorConstructor() {return function(target: any) {console.log('simpleDecoratorConstructor');}}@simpleDecorator// simpleDecorator 会附在A身上,当A加载就会调用 simpleDecorator// 注意有多个装饰器,靠近 A 的装饰器先触发class A {// 注意装饰器后的代码返回一个函数即可// simpleDecoratorConstructor 返回的函数会替换 getTarget 函数体@simpleDecoratorConstructor()getTarget(params: any) {console.log('A getTarget');}} // "hi"console.log('simpleDecorator', new A().getTarget(1));

4、declare

// declare 关键字// 当外部模块的变量没有类型,可以使用 declare 关键字声明变量类型// 不能赋值, 只能定义类型// declare let module_declare: string = 'hello'; // 报错declare let module_declare: string;module_declare = 'hello'; // 正确// declare module NAMEdeclare module 'antd' {export function message(content: string): void;}declare module '@ant-design/icons' {export function message(content: string): void;}// 强制模块export {};// 全局对象扩展// 注意,只能扩展属性,不能新增顶层对象declare global {interface String {toRaw(): string;}}String.prototype.toRaw = ():string => {return 'toRaw';};

5、运算符

    // 运算符type T5 = {name: string;age: number;};// 返回所有的属性名(可能找到原型链上)type T6 = keyof T5; // T6 是联合类型 "name" | "age"const t6: T6 = 'name'; // 正确,keyof T5 返回 T5 的属性名类型// 一般需要使用对象属性的时候使用,keyof 返回 属性名的联合类型const T7_Obj = {name: 'vbj',age: 18,};const T7_Key: string = 'name';function T7_Func(obj: T5, key: string) {return obj[key as keyof T5];}T7_Func(T7_Obj, T7_Key)// in 运算符 (类型中,而不是js的in运算符)type Type8 = {name: string;age: number;};// 类似于复制所有目标对象的属性到一个新对象中type Type9 = {[key in keyof Type8]: any;};// 方括号// 获取类型的属性值type Type10 = {name: string;age: number;[key:number]: boolean};// 因为是类型括号,所以括号中也可以穿入类型(类型括号不能变量值)// type Type = Type10['na' + 'me'] // 报错type Type10_number = Type10[number] // booleantype Type11 = Type10['name'] // string// 联合类型,也会被识别成联合类型type Type12 = Type10['name'|'age'] // string | number// extends 三元运算符// 条件判断,根据类型判断返回不同类型;公式:T extends U ? X : Y// T 是 U 的子类型,返回 X;否则,返回 Ytype Type13 = string extends string | number? string : number; // string// infer 关键字// infer 关键字可以帮助我们推导类型变量;这样可以得到一个主动推导的变量类型(element)type type14<Type> = Type extends Array<infer element> ? element : string;type type15 = type14<string[]>; // string// is 关键字// is 关键字可以判断一个变量是否是某个类型;相当于语义化,具体判断需要自行定义function isType10(a:string): a is string {console.log('isType10 Function');return typeof a ==='string';}if(isType10('isType10_result')){console.log('isType10_result');}// 类型中的字符串模板type Type16 = `hello ${string} world`; // "hello " + string + " world"// satisfies 关键字// 手动类型检测, 帮助你进行类型报错提示type Type17 = {name: string;age: number;};// 这里并不想指定类型,而使用默认推导;但是又希望推导的时候,能够进行属性校验// 主要是为了获取开发时的提示const Type17_Obj = {name: 'vbj',aeg: 18,count: 100,} satisfies Type17;const Type17_count = Type17_Obj.count;

6、映射类型

    // 映射类型// 映射类型可以帮助我们快速创建类型;// 语法:{ [K in keyof T]: X }// 其中,K 是 T 的属性名,X 是任意类型type Type18 = {name: string;readonly age: number;};// 注意前面的+、-、readonly,表示修改关键字,增加或去除只读性// +、-、?,表示增加或去除可选性type Type19 = {// count: number; // 如果映射,不能添加新属性// A as B 可以在之前的键名A基础上转换属性名B+readonly[P in keyof Type18 as `newkey ${P}`]+?: Type18[P];};

7、类型工具

    // 类型工具type Type20 = {name: string;age: number;}// 工具类型类似于语法糖// type Partial<T> = { [P in keyof T]?: T[P] | undefined; }type TypeTool1 = Partial<Type20>; // 所有属性可选type TypeTool2 = Required<Type20>; // 所有属性必填type TypeTool3 = Readonly<Type20>; // 所有属性只读type TypeTool4 = Pick<Type20, 'name' | 'age'>; // 选择性的属性type TypeTool5 = Omit<Type20, 'age'>; // 排除的属性 返回剩下的属性type TypeTool9 = Parameters<() => void>; // 参数类型 可以传入函数类型type TypeTool10 = ReturnType<() => string>; // 返回值类型 可以传入函数类型type TypeString1 = 'hello'type TypeString2 = Uppercase<TypeString1> // HELLO 字符串类类型大小写转换// 使用频率较高的类型工具// 快速创建未知数量属性的对象类型type Type21 = Record<string, any>; // 索引类型,可以指定索引类型

8、语法注释

    // 语法注释// @ts-nocheck 忽略检查const element = document.getElementById(123);// JSDoc 声明// JSDoc 注释可以帮助我们生成文档,同时也会帮助我们进行类型检查// 注意类型变量放在{}中/*** @param {string} name 这里的类型只是说明参数类型,不是实际类型; * @typedef {(number | string)} NumberLike 相当于创建type别名* @typed {NumberLike} 描述类型是什么,使用刚才定义的别名* @returns {void} 这里的类型只是说明返回值类型,不是实际类型;* @extends {HTMLElement} 继承自HTMLElement*/function NoteFun(name: number): string {console.log('Hello ' + name);return 'Hello';}

9、tsconfig.json

// tsconfig.json
//npm install -g typescript
// tsc --init 生成tsconfig.json文件
// 打包编译时会读取tsconfig.json配置
{"compilerOptions": {"outDir": "./dist", // 编译输出目录"allowJs": true, // 允许编译js文件"target": "es5", // 编译js的目标版本"jsx": "react", // 使用jsx, 规定输出的jsx文件名"lib": ["dom", "es2021"], // 编译时需要引入的内置的类型库"sourceMap": true, // 生成sourceMap文件"strict": true, // 开启严格模式"paths": {"@/*": ["src/*"] // 路径映射, 类似于webpack的resolve.alias}},"include": ["./src/**/*"] // 需要编译的文件列表
}

相关文章:

前端TS基础

文章目录 一、类型1、定义类型2、any、unknown、never3、基础类型4、联合类型5、交叉类型6、type、typeof7、作用域 二、数据结构1、数组2、元组3、函数类型4、对象类型 三、接口四、泛型五、enum六、断言七、工具1、模块2、namespace3、装饰器4、declare5、运算符6、映射类型7…...

前端面经每日一题day06

Cookie有什么字段 Name&#xff1a;cookie的唯一标识符 Value&#xff1a;与Name对应&#xff0c;存储Cookie的信息 Domain&#xff1a;可以访问cookie的域名 Path&#xff1a;可以访问cookie的路径 Expires/Max-Age&#xff1a;超时时间 Size&#xff1a;cookie大小 Ht…...

SOC,SOH含义区别及计算公式

SOC&#xff0c;SOH含义区别及计算公式 两者结合使用&#xff0c;有助于实现更精确的电池管理&#xff0c;延长电池的使用寿命&#xff0c;并确保电池的高效、安全运行。 1. SOC&#xff08;State of Charge&#xff0c;荷电状态&#xff09;2. SOH&#xff08;State of Health…...

阿里云轻量应用服务器开放端口,图文教程分享

阿里云轻量应用服务器如何开放端口&#xff1f;在轻量服务器管理控制台的防火墙中添加规则即可开通端口&#xff0c;开通80端口就填80&#xff0c;开通443就填443端口&#xff0c;开通3306端口就填3306。阿里云百科网aliyunbaike.com整理阿里云轻量应用服务器端口号开通图文教程…...

嵌入式里的“移植”概念

这里因为最近一年看到公司某项目很多代码上有直接硬件的操作&#xff0c;这里有感而发&#xff0c;介绍移植的概念。 一、硬件 先上一个图&#xff1a; 举个例子&#xff0c;大学里应该都买过开发板&#xff0c;例如st的&#xff0c;这里三个层次&#xff0c; 内核&#xff…...

深入探讨 AF_PACKET 套接字

AF_PACKET 套接字是一种用于直接访问网络接口(即网卡)的套接字类型&#xff0c;通常用于网络数据包捕获和分析。它允许应用程序直接与网络接口卡&#xff08;NIC&#xff09;交互&#xff0c;而不需要通过网络协议栈。从而可以发送和接收以太网帧。它提供了比普通TCP/UDP套接字…...

Redis的哨兵机制

目录 1. 文章前言2. 基本概念2.1 主从复制的问题2.2 人工恢复主节点故障2.3 哨兵机制自动恢复主节点故障 3. 安装部署哨兵&#xff08;基于docker&#xff09;3.1 安装docker3.2 编排redis主从节点3.3 编排redis-sentinel节点 4. 重新选举5. 选举原理6. 总结 1. 文章前言 &…...

CSS系列(1)-- 选择器体系详解

前端技术探索系列&#xff1a;CSS 选择器体系详解 &#x1f3af; 致读者&#xff1a;探索 CSS 选择器的奥秘 &#x1f44b; 前端开发者们&#xff0c; 今天我们将深入探讨 CSS 选择器体系&#xff0c;这是构建优雅样式表的基础。让我们一起学习如何精确地选中并控制网页中的…...

用Python开发打字速度测试小游戏

本文将带你一步步开发一个简单的打字速度测试小游戏,通过随机生成词组并计算用户输入速度,帮助提升打字技能。 一、功能描述 随机生成一段句子,用户需要尽快输入。计时功能,统计用户输入的总时长。对比正确率和速度,给出评分反馈。二、开发环境 语言:Python依赖库:pygam…...

基于gitlab API刷新MR的commit的指定status

场景介绍 自己部署的gitlab Jenkins,并已经设置好联动(如何设置可以在网上很容易搜到)每个MergeRequest都可以触发多个Jenkins pipeline&#xff0c;pipeline结束后会将状态更新到gitlab这个MR上希望可以跳过pipeline运行&#xff0c;直接将指定的MR的指定pipeline状态刷新为…...

服务器数据恢复—LINUX下各文件系统删除/格式化的数据恢复可行性分析

Linux操作系统是世界上流行的操作系统之一&#xff0c;被广泛用于服务器、个人电脑、移动设备和嵌入式系统。Linux系统下数据被误删除或者误格式化的问题非常普遍。下面北亚企安数据恢复工程师简单聊一下基于linux的文件系统&#xff08;EXT2/EXT3/EXT4/Reiserfs/Xfs&#xff0…...

Spark on Yarn安装配置,大数据技能竞赛(容器环境)

Spark on Yarn模式&#xff0c;即把Spark作为一个客户端&#xff0c;将作业提交给Yarn服务&#xff0c;由于在生产环境中&#xff0c;很多时候都要与Hadoop使用同一个集群&#xff0c;因此采用Yarn来管理资源调度&#xff0c;可以有效提高资源利用率。 环境说明&#xff1a; 服…...

遣其欲,而心自静 -- 33DAI

显然&#xff0c;死做枚举只能的50分。 错了4次总算对了。 大体思路&#xff1a; 因题目说只有两个因数&#xff0c;那么有两种情况&#xff1a; 1&#xff1a;两个质数相乘&#xff0c;如&#xff1a;3*515 5*745 等&#xff08;不包括5*525 或5*315 重复计算\ 因为3*5算了…...

No.25 笔记 | 信息收集与Google语法的实践应用

什么是信息收集&#xff1f; 信息收集&#xff08;Information Gathering&#xff09;是渗透测试的第一步&#xff0c;其目的是通过各种手段收集目标的漏洞和弱点&#xff0c;为后续的攻击策略提供依据。 正所谓“知己知彼&#xff0c;百战百胜”&#xff0c;信息收集的重要性…...

GitLab基础环境部署:Ubuntu 22.04.5系统在线安装GitLab 17.5.2实操手册

文章目录 GitLab基础环境部署&#xff1a;Ubuntu 22.04.5系统在线安装GitLab 17.5.2实操手册一、环境准备1.1 机器规划1.2 环境配置1.2.1 设置主机名1.2.2 停止和禁用防火墙1.2.3 更新系统 二、GitLab安装配置2.1 安装GitLab所需的依赖包2.2 添加GitLab存储库2.2.1 将GitLab存储…...

SpringBoot3配置文件

一、统一配置管理概述: SpringBoot工程下&#xff0c;进行统一的配置管理&#xff0c;你想设置的任何参数(端口号、项目根路径、数据库连接信息等等)都集中到一个固定位置和命名的配置文件(application.properties或application.yml)中 配置文件应该放置在Spring Boot工程的s…...

【机器学习】任务十二:循环神经网络

1.循环神经网络 1.1 什么是循环神经网络&#xff08;RNN&#xff09;&#xff1f; 循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09; 是一种用于处理序列数据的神经网络类型&#xff0c;它的主要特点是拥有循环连接&#xff0c;使得网络可以对序列中的每个…...

【返璞归真】-切比雪夫不等式(Chebyshev‘s Inequality)

切比雪夫不等式&#xff08;Chebyshev’s Inequality&#xff09; 切比雪夫不等式是概率论中的一个基本不等式&#xff0c;用于估计随机变量偏离其期望值一定范围的概率。它对于任何具有有限期望和有限方差的随机变量都成立。 公式表达 切比雪夫不等式的基本形式如下&#xf…...

【Django】在view中调用channel来主动进行websocket通信

前提&#xff1a;consumer中已经写好了建立连接的代码&#xff0c;并且能够成功把连接加入到通道层的组内 可以参考我的另一个博客&#xff1a; LuckySheet协同编辑后端示例(DjangoChannel,Websocket通信)_lucksheet 协同编辑-CSDN博客 我是懒得去折腾luckysheet的源码&…...

18.[极客大挑战 2019]BabySQL1

进入靶场 随便输输 再输输 可以判断是单引号闭合 再随便输输 查询字段数量 得&#xff0c;过滤了 关键字也过滤了 只能双写了 根据回显&#xff0c;这样可以&#xff0c;只是需要改改 1,2不行 1,2,3行 1,2,3,4不行 可以尝试得到库名&#xff0c;表名了 库名 database(…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...

k8s从入门到放弃之HPA控制器

k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率&#xff08;或其他自定义指标&#xff09;来调整这些对象的规模&#xff0c;从而帮助应用程序在负…...

《信号与系统》第 6 章 信号与系统的时域和频域特性

目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...