前端提升3:TS
2025-03-15 10:19:14TypeScript 是一种由微软开发的自由开源的编程语言,他是JavaScript的一个超集,扩展了JavaScript的 语法,主要提供了类型系统和对 ES6 的支持。
一、类型定义
window.onload=function(){
//类型系统
let flag:boolean = false; //布尔类型
let num:number = 15; //数值类型
let str:string = 'abc'; //字符串类型
let str2:string=`hello,${str}`;
let msg:string = `hello,${str},${num}`;
let u: undefined = undefined;
let n: null = null;
//为什么要TS
// function sum(n1:number,n2:number){
// return n1+n2
// };
// sum(10,20);
// sum('10',20);
let count:number = 10;
count = 100;
//声明的变量有多种类型——联合类型
let id:number | string = 10;
id = '111';
//任意类型 :any 万能类型
let x:any = true;
x = 111;
x = 'abc';
//引用类型
//数组
let arr:number[] = [1,2,3,4,5];
//最简单的方法是使用「类型 + 方括号」来表示数组: number[]
let arr2:string[] = ['a','b','hello'];
let arr3:(number|string)[] = ['a',100,'hello'];
let arr4:any[] = ['a',100,'hello'];
//数组泛型 Array<类型>
let arr5:Array<number>= [1,2,3,4,5];
let arr6:Array<string>= ['a','b','hello'];
let arr7:Array<number|string> = ['a',100,'hello'];
let arr8:Array<any> = ['a',100,'hello'];
//对象
//接口 interface 合同
// 在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象
// 接口(Interfaces)可以用于对「对象的形状(Shape)」进行描述。
interface IPerson { //定义接口 首字母大写,在项目实战中,习惯在接口前添加I
//变量的声明
//方法的声明
id:number; //确定属性(必填)
name:string; //确定属性(必填)
}
let obj: IPerson = { //受到接口的约束
id:1,
name:'John'
}
let tom :IPerson ={
id:10,
name:'tom'
}
//扩展
let items:Array<IPerson> = [{id:1,name:'a'},{id:2,name:'b'},{id:3,name:'c'}];
let items2:IPerson[] = [{id:1,name:'a'},{id:2,name:'b'},{id:3,name:'c'}];
let items3:Array<{id:number,name:string}> = [{id:1,name:'a'},{id:2,name:'b'},{id:3,name:'c'}];
//函数 输入类型(参数类型)和输出类型(返回值)
function sum2(n1:number,n2:number):number{
return n1+n2
};
sum2(10,20);
let sum3 = (n1:number,n2:number):number=>n1+n2;
sum3(100,20);
//无返回值
function sum4(n1:number,n2:number):void{
if(n1>n2){
console.log('n1>n2')
}
};
sum4(20,10);
//默认值
let sum5 = (n1:number=1,n2:number=1):number=>n1+n2;
sum5(100,20);
sum5();
//选填参数
let sum6 = (n1:number=1,n2?:number):number=>n2?n1+n2:n1;
sum6(100);
//常见的写法
const fn1 =(x,y)=>[x,y];
//添加类型
const fn2 = (x:string,y:string):Array<string>=>[x,y]
fn2('hello','abc')
//定义对象
interface IPerson2{
id:number;
name:string;
age:number;
}
interface IOther {
pid:number;
title:string;
}
const o1:IPerson2 = {id:1,name:'Lily',age:18};
const fn3 = ({id,name}:IPerson2):IOther=>({pid:id,title:name})
fn3(o1);
//过滤
//[1,2,3,4,5] 过滤
const items4:Array<number> = [1,2,3,4,5];
const filter:number[] = items4.filter((item:number):boolean =>item>3); //[4,5]
console.log(filter);
//求和
const total:number = items4.reduce((total:number,cur:number):number=>total+cur,0);
console.log(total)
//类型别名
function myHello(person: n) {
return 'Hello, ' + person;
};
type n = number;
let name:n = 18;
console.log(myHello(name));
}
二、类的实现
1. 类的定义
window.onload=function(){
//类的定义,类的类型,类继承的类型
class Cat1 {
//属性声明
name:string;
color:string;
constructor(name:string,color:string){
this.name = name;
this.color = color;
}
eat(v:string):string {
return v;
}
};
let c1 = new Cat1('jack','black');
console.log(c1.name) //jack
//类受到接口的约束
interface IFeatures {
name:string;
age:number;
action?():string;
}
//类实现接口
class Person implements IFeatures {
name:string;
age:number;
msg:string;
constructor(name,age){
this.name = name;
this.age = age;
this.msg = 'hello'
}
action(){
return 'action'
}
};
let p1 = new Person('john',20);
//类继承 实现
//场景:
//1、车对象 拥有特性:报警的功能+灯光系统
//2、门对象 有子对象,防盗门 防火门。。 拥有特性:报警的功能
//报警的功能
interface IAlarm{
sing(bell:string):string;
}
//灯光系统
interface ILight {
lightOn();
lightOff():boolean;
}
//定义类对象
//门
class Door {
type:string;
constructor(type){
this.type = type;
}
};
//防盗门 继承门的特性 实现报警的功能
class SecurityDoor extends Door implements IAlarm{
constructor(type:string){
super(type)
}
sing(bell){return bell}
}
let s1 = new SecurityDoor('abc');
s1.type
s1.sing('dididi');
//车 拥有特性:报警的功能+灯光系统
class Car implements IAlarm, ILight{
height:number;
color:string;
constructor(height,color){
this.height = height;
this.color = color;
}
sing(v){return v}
lightOn(){}
lightOff(){return true}
};
}
2. 修饰符
window.onload=function(){
//public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的;
class Cat1 {
//属性声明
public name:string;
public color:string;
constructor(name:string,color:string){
this.name = name;
this.color = color;
}
public eat(v:string):string {
return v;
}
};
let c1 = new Cat1('jack','black');
console.log(c1.name) //jack
c1.eat('eat')
//private 修饰的属性或方法是私有的,不能在声明它的类的外部访问;
//私有的 只能在类内部访问,子类或类的实例都无法访问
class Cat2 {
//属性声明
private name:string;
public color:string;
constructor(name:string,color:string){
this.name = name;
this.color = color;
}
private say():void {
console.log(`my name is ${this.name}`) //只能在类内部访问
}
};
let c2 = new Cat2('jack','black');
//c2.name //error
//c2.say()
class Test extends Cat2{
constructor(name:string,color:string){
super(name,color)
}
action(){
console.log(this.name) //报错 子类无法访问
}
};
let t1 = new Test('jack','black')
//protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的;
//受保护的 子类中也是允许被访问的,但不能在类的实例中访问
class Cat3 {
//属性声明
protected name:string;
public color:string;
constructor(name:string,color:string){
this.name = name;
this.color = color;
}
protected say():void {
console.log(`my name is ${this.name}`) //只能在类内部访问
}
};
let c3 = new Cat3('jack','black');
c3.name; //报错 不能在类的实例中访问
class Test3 extends Cat3{
constructor(name:string,color:string){
super(name,color)
}
action(){
console.log(this.name) //子类可以访问
}
};
let t3 = new Test3('jack','black')
//扩展
class Employee {
//属性声明
protected salary:number;
public name:string;
constructor(name:string,salary:number){
this.salary = salary;
this.name = name;
}
public say():number {
console.log(this.salary);
return this.salary
}
};
let employee1 = new Employee('jack',10000);
//employee1.salary //报错
employee1.say() //10000
//4、static 静态方法,作用:不需要实例化,直接通过类来调用
class Employee2 {
//属性声明
static salary:number=20;
public name:string;
constructor(name:string,salary:number){
this.name = name;
}
static say() {
console.log(Employee2.salary)
}
};
//let employee2 = new Employee2('jack',10000);
//employee2.say(); //报错
Employee2.say(); //20 不需要实例化,直接通过类来调用
//5、只读修饰符readonly
class Employee3 {
//属性声明
readonly salary:number=2000;
public name:string;
constructor(name:string,salary:number){
this.name = name;
this.salary = salary; //只有在类的构造函数中才能进行赋值修改
}
public say() {
this.salary = 20000; //由于是只读,不能修改
}
};
let employee3 = new Employee3('jack',10000);
employee3.salary = 50000; ////由于是只读,不能修改
}
三、泛型
window.onload=function(){
//泛型
//数组泛型 Array<类型>
//为什么要泛型
function fn1(a:number,b:number):number[]{
return [a,b]
};
fn1(10,20);
function fn2(a:string,b:string):string[]{
return [a,b]
};
fn2('hello','fn2');
function fn3(a:boolean,b:boolean):boolean[]{
return [a,b]
};
fn3(true,false);
//类型是变量T
function fn4<T>(a:T,b:T):T[]{
return [a,b]
};
fn4<number>(10,20);
fn4<string>('hello','fn2');
fn4<boolean>(true,false);
//扩展
// function fn5<T>(str:T):number{
// return str.length
// };
// fn5<string>('hello');
//解决:泛型约束 extends
//泛型变量T进行约束 限制泛型的类型 使用接口
interface ILength {
length:number;
}
//传入的类型必须有length属性
function fn6<T extends ILength>(str:T):number{
return str.length
};
fn6<string>('hello');
fn6<number>(100); //error
fn6<number[]>([1,2,3,4,5])
fn6<Array<number>>([1,2,3,4,5]);
fn6<ILength>({length:10})
fn6<{length:number,id:number}>({length:10,id:1})
//扩展
interface INamed {
name:string;
[propName:string]:any;
};
//传参数必须有name属性
function getName<T extends INamed>(obj:T):string{
return obj.name
};
getName<INamed>({name:'tom',age:18})
getName<INamed>({title:'tom',age:18})
//泛型在函数中的写法
//函数声明
function f7<T>(n1:T,n2:T):T[]{
return [n1,n2]
}
//函数表达式
let f8 = function<U>(n1:U,n2:U):Array<U>{
return [n1,n2]
}
//箭头函数
let f9 = <U>(n1:U,n2:U):Array<U>=>[n1,n2];
//多个参数
interface IMultiple<T,U>{
first:T;
second:U;
}
const multiple1:IMultiple<number,string> = {
first:1,
second:'two'
}
const multiple2:IMultiple<boolean,number> = {
first:true,
second:100
}
//扩展
let f10 = <N,S>(arr:[N,S]):[S,N]=>[arr[1],arr[0]];
f10<number,string>([100,'hello']);
let f11 = <N,S>(n1:N,n2:S):[S,N]=>[n2,n1];
//let f12 = <泛型变量1,泛型变量2>(形参1,形参2):返回值类型=>函数体,返回结果;
//泛型接口:在定义接口时使用泛型类型
//具体理解
//定义函数1
// let fun1 = function(s1,s2){
// return s1===s2
// };
// fun1(100,'100');
// //定义函数2
// let fun2 = function(x,y){
// if(x>y){
// return true;
// }else {
// return false;
// }
// };
// fun2(100,200);
//以上函数逻辑不同,类型有什么不一样
// //定义函数1
// let fun1 = function(s1:number,s2:number):boolean{
// return s1===s2
// };
// fun1(100,100);
// //定义函数2
// let fun2 = function(x:number,y:number):boolean{
// if(x>y){
// return true;
// }else {
// return false;
// }
// };
// fun2(100,200);
//共同点:传入二个参数,返回boolean
// interface IInspectFunc {
// (a:number,b:number):boolean;
// }
// //定义函数1
// let fun1:IInspectFunc = function(s1,s2){
// return s1===s2
// };
// fun1(100,100);
// //定义函数2
// let fun2:IInspectFunc = function(x,y){
// if(x>y){
// return true;
// }else {
// return false;
// }
// };
// fun2(100,200);
//为什么要用到接口?复用+抽离+灵活+扩展+简洁。。。
//泛型用到了接口中 泛型接口:在定义接口时使用泛型类型
// interface IInspectFunc {
// <T>(a:T,b:T):boolean;
// }
// //定义函数1
// let fun1:IInspectFunc = (s1,s2)=>s1===s2;
// fun1<string>('100','120');
// //定义函数2
// let fun2:IInspectFunc = (x,y)=>x>y?true:false;
// fun2<number>(100,200);
//另一种写法:泛型参数提前到接口名上
interface IInspectFunc<T> {
(a:T,b:T):boolean;
}
//定义函数1
let fun1:IInspectFunc<string> = (s1,s2)=>s1===s2;
fun1('100','120');
//定义函数2
let fun2:IInspectFunc<number> = (x,y)=>x>y?true:false;
fun2(100,200);
//扩展2 定义一个函数,传入长度和值,返回数组(数组的长度是传入的长度,数组的值传入的参数)
// let createArray = function<T>(len:number,v:T):Array<T>{
// let arr:T[]= [];
// for(let i=0;i<len;i++){
// arr[i] = v;
// };
// return arr;
// }
// createArray<string>(5,'hello'); //['hello','hello','hello','hello','hello']
// createArray<number>(3,100); //[100,100,100]
//抽离 输入类型和输出类型
interface ICreateArr {
<T>(len:number,v:T):Array<T>
}
let createArray :ICreateArr = function<T>(len,v){
let arr:T[]= [];
for(let i=0;i<len;i++){
arr[i] = v;
};
return arr;
}
createArray<string>(5,'hello'); //['hello','hello','hello','hello','hello']
createArray<number>(3,100);
//另一种写法
let createArray2:ICreateArr = <T>(len,v)=>Array<T>(len).fill(v);
}
四、类型断言
window.onload=function(){
//type 和interface的区别
//type 类型别名 为类型起新的名字
type abc = string;
let s:abc = 'hello'; //===?let s:string = 'hello'
type xyz = number|string|boolean;
let a:xyz = 100;
let fn = (v:xyz):abc=>'v';
type Person = {
name:abc;
age:number;
};
let o1:Person = {
name:'o1',
age:20
}
let o2:{name:string;age:number}= {
name:'o1',
age:20
}
//支持字面量表示
type Shape = {
kind?:'circle';
radius:number;
};
const circle:Shape = {kind:'circle',radius:10};
//const circle:Shape = {kind:'abc',radius:10};
//type定义联合类型
type Shape2 = {
kind:'circle';
radius:number;
} | {
kind:'square';
weight:number;
};
const circle2:Shape2 = {kind:'square',weight:10};
const circle3:Shape2 = {kind:'circle',radius:10};
//交叉类型
type TName = {
name:string;
}
type TAction = {
action(v:string):void
}
//同时二个type
type Test = TName & TAction;
const o5:Test = {
name:'john',
action(v:string):void{
console.log(`${v} ${this.name}`)
}
};
o5.action('hello ')
//interface和type ,interface会合并,type不同
interface IPerson {
name:string;
}
interface IPerson {
age:number;
};
const p:IPerson ={
name:'p',
age:20
}
}
五、枚举
window.onload=function(){
//枚举
//enum类型是对JavaScript标准数据类型的一个补充
let arr = ['red','green','blue'];
arr['red'] //error
let o1 = {
red:0,
green:1,
blue:2
};
//o1.red o1['red']
o1[0] //error
//枚举定义
//enum 枚举名称 {成员1,成员2,成员3}
enum Color {Red,Green,Blue};
//获取属性名获取
//console.log(Color.Red) //0 获取索引
//成员值0,转换为对应的属性名称
console.log(Color[0]) //'Red'
//总结:枚举类型可以视为具有二个属性的对象:名称到值的映射、值到名称的映射;
//作为类型添加
let c1:Color = Color.Blue;
let c2:string = Color[0];
//修改枚举类型
//Color.Green = 5; //不能修改,是只读
//具体使用场景
enum Day {
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Frisday,
Saturday
};
//函数的返回值
function fn():Day{
let n = new Date().getDay(); //5
if(n===Day.Saturday ||n===Day.Sunday ){
console.log('休息')
}else {
console.log('上班')
}
return n;
};
fn()
//扩展
enum Color2 {Red,Green,Blue};
function getColorName(color:Color2):string{
switch (color){
case Color2.Red:
return '红色';
case Color2.Green:
return '绿色';
case Color2.Blue:
return '蓝色';
default:
return '其它颜色'
}
};
getColorName(2)
// getColorName(3) //error
//更多灵活性
//1、数字枚举
enum Color3 {
Red = 1,
Green = 10,
Blue = 15
};
//console.log(Color3[10]) //'Green'
console.log(Color3.Blue) //15
//2、小数枚举
enum Color4 {
Red = 1.6,
Green ,
Blue
};
console.log(Color4.Blue) //3.6
//4、字符串枚举
enum Color5 {
Red = 'red',
Green = 'green',
Blue= 'blue'
};
console.log(Color5.Blue) ///'blue'
//5、任意值枚举
let count = 888;
enum Color6 {
Red = 'red',
Green = 'green'.length,
Blue= <any>count
};
console.log(Color6.Blue) //888
}
六、元祖
window.onload=function(){
//元组
//数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。
//数组
let arr1:number[] = [1,2,3,4,5];
let arr2:Array<string> = ['a','b','c'];
let arr3:(number|string)[] = [1,2,3,'4','5'];
let arr4:Array<any> = ['a',100,true];
const items = ['a',100,true];
let arr5:Array<any> = items;
//元组的定义
let tuple1:[string,number,boolean] = ['a',100,true];
//常用的写法
let tuple2:[number,string] =[100,'hello'];
let tuple3:[number,[number,number]] =[100,[1,2]];
let tuple4:[number,Array<number>] =[100,[1,2,3,4,5]];
//对象
interface IPerson{
name:string;
age:number;
};
let o1 :[IPerson]= [{name:'o1',age:20}];
let o2 :IPerson[]= [{name:'o1',age:20}];
let o3 :[IPerson,boolean,Array<number>]= [{name:'o1',age:20},true,[1,2,3,4]];
//使用场景:
let person:[string,number] = ['John',20];
//扩展:
//处理多个返回值,定义数组,返回最小值和最大值
let numbers:Array<number> = [5,2,10,8,3];
function fn(arr:number[]):[number,number]{
let min = arr[0];
let max = arr[0];
for(const n of arr){
if(n < min){
min = n;
};
if(n>max){
max = n;
};
};
return [min,max];
}
const [min,max] = fn(numbers);
console.log(min);
console.log(max);
}