基础类型
1、unknown和as类型转换
// 当有字符串类型变量需要转换为数值类型时
let string : string = '999'
let num = string as unknown as number
同时,使用unknown类型声明的变量的方法也不能被使用
let unk : unknown = 'this is an unknown variable'
unk.slice(1) // error
unknown虽然不是任何类型,但是也不允许赋值给任何类型变量
let unk : unknown = 'this is an unknown variable'
let str : string = unk // error
2、void
当函数没有明确返回值(即返回null或undefinded时),允许使用void类型约束函数
function v : void (){}
function v : void (){ return }
function v : void (){return null}
function v : void (){return undefined}
function v : void (){ console.log() }
function v : void (){return true} // error
void也允许用来约束变量,但只允许分配null、undefinded和void类型的值
let val : void
let val : void = null
let val : void = undefined
3、never
never指永不可被赋值的变量,或永不会有返回结果的函数。但是什么情况下才会有不会返回结果的函数?
function ne : never(){
throw new Error('程序错误')
// 或是永不退出的循环
while(true){}
}
// 但是当函数有几乎到达结束时,never将会报错
function ne : never(){
if(num>10){
throw new Error('程序错误')
}
} // error
函数
1、函数参数定义
当多个函数的参数定义重复时,使用type来定义参数是个很好的选择
// 定义公共参数
type userInfo = { name:string , age:number , sex?:string|number } // 性别为选填,且可为数字或字符串
function showUser (user:userInfo){
...
}
function updateUser (user:userInfo){
...
}
2、函数结构约束
type不仅可以用来约束函数的参数,也可以用来约束函数的结构
type userInfo = { name:string , age:number , sex?:string }
type showResult = ( user:userInfo ) => boolean
// 至此,就可以用showResult来约束函数的结构必须和其相同
let updateUserInfo:showResult = ( u:userInfo ):boolean =>{
...
return true
}
3、剩余参数
在JS中,可以使用...语法来接收长度不确定的参数,TS中也同样可以,而且也可以约束其类型
function log( ...args:number[] ){
return args.reduce( (p,n) => p+n ,0 )
}
log( 1,2,3,4,5 )
4、元组
在某些情况下,可能需要对数组中的某个参数进行类型约束,这时就可以使用元组
type tuple = [ string , number ]
let arr = [ '男' , 23 ] // true
let arr = [ 23 , '男' ] // false
5、枚举
在TS中,允许为一组数据命名,以方便查找对应的映射
enum color { red:1 , blue , green , yellow }
let c = color[2] // blue
let g = color.green // 3
6、断言 as const
在TS中,使用断言可以将变量约束为某一类型甚至某一个值,而as const则更加强力,可以约束变量的同时使其无法被修改
let str = '这是const' as const
str = '这是let' // error
哪怕是将变量作为值赋值给对象,也不能被修改
let str = '这是const' as const
let obj = {
name : str
} // name的值为`这是const`
obj.name = '这是let' // error
如果变量没有被设置为as const的话,将作为类型赋值给属性
let str:string = '这是let'
let obj = {
name : str
} as const // name没有被赋值,为string类型,且不允许被赋值
如果对象或数组使用了as const,就是将其设置为了只读,不允许修改
let arr = [ 1 , '2' , true ] as const
arr[2] = '修改第二个' // error
假如不对数组进行as const限制的话,如果变量从数据中取值的类型将会是不确定的
let arr = [ 1 , '2' , false ]
let a = arr[1]
// 此时a的类型是[string|number|boolean],因此可以给他赋三个类型中的任意值
a = 2 // true
a = 'str' // true
a = true // true
但是如果给数据进行as const限制的话,变量从数据中取值就会被指定类型
let arr = [ 1 , '2' , true ]
let a = arr[2]
// 此时a的类型被指定为boolean类型
a = 2 // false
a = 'str' // false
a = false // true
as cosnt的实际运用
当方法有多个返回值且被集成为一个数组时,可以使用断言结合解构语法来准确的获得值
function show() {
let a = '这是一个string'
let b = (x: number, y: number): number => x + y
return [a,b] as const
/*
也可以使用其他方法
1. return [ a , b ] as [ typeof a , typeof b ]
2. return [ a , b ] as [ String , Function ]
*/
}
let [ str , fnc ] = show()
/*
如果在函数返回值中没有使用`as const`,也可以在函数执行的时候用元组规定返回值类型
1. show() as [ string , function ]
2. show() as [ string , ( x:number , y:number)=>number ]
注意!!!不能使用 show() as const
由于as const只能对明确类型的变量使用,在函数返回值中的类型是不明确的,无法准确地约束类型
*/
fnc( 1 , 2 ) // 3
7、非空断言
在某些情况下,当获取的值被编译器判定不确定是否存在时,会自动为变量约束一个null类型
<!-- 有一个div需要被更改内容 -->
<div id="fake-div">
这是一个span
</div>
/* 如果直接获取的话,变量就会同时拥有null和Element两种类型 */
let div:HTMLDivElement = document.querySelector('.fake-div')
/*
如果开启了严格校验不允许赋值为null,可以设置两种类型
但是如果这样设置的话,在接下来使用div变量时,编译器将不会自动补全HTML语法
*/
let div:HTMLDivElement | null = document.querySelector('.fake-div')
非空断言应使用于无法判断是null或者具体类型的情况下,用来为获取不确定是否存在值的对象指定具体类型
// 可以使用两种方法来约束其只有一种类型
// 1.断言
let div:HTMLDivElement = document.querySelector('.fake-div') as HTMLDivElement
// 2.非空断言
let div:HTMLDivElement = document.querySelector('.fake-div')!
// 此时,div变量的类型就只有HTMLDivElement了
8、构造函数断言
在构造函数中,也可以对实例的属性进行类型约束
class person {
el:HTMLDivElement
constructor(el:HTMLDivElement) {
this.el=el
}
}
let man = new person('str') // error
let div = document.querySelector('div') as HTMLDivElement
let girl = new person(div) // true
小tips
使用TS时,尽可能为变量约束具体的类型,这样方便编译器提供更具体的代码补全功能
类
1、类型约束类
JS的类也可以使用类型进行属性约束
class person{
name:string
age:number
constructor( n:string , a:number ){
this.name=n
this.age=a
}
showInfo(){
return `${this.name}的年龄为${this.age}`
}
}
// 还可以用一个约束实例对象的数据,来装载特定的势力对像
let man :person[] = [ pereson('hqh',21) , person('jxy',21) ] // 只允许由person创建的实例对象插入
2、泛型
之前所使用的都是指定的类型(str:string),但是如果需要动态的判断类型呢?这时就可以使用泛型
function show <a> ( arg:a ):a{
return arg
}
let str = show <string>('string')
let num = show <number>(123)
let boo = show <boolean>(true)
let boo2 = show (false) // 自动判断为boolean类型
注意!泛型并不能准确的判断出每一种类型,还是需要调用时详细指明类型!
3、泛型约束
当函数返回的值是某个类型的特征时(如length属性),此时需要为泛型指定包含该特征的类型
function show<t extends String | number[]>(para: t): number {
return para.length;
}
show([1, 2, 3]) // 3
show('this is a string') // 16
show(123) // error number类型没有length属性
// 也可以自定义需要约束的特征,也有同样的效果
type newType = { length: number }
function show<t extends newType>(para: t): number {
return para.length;
}
// 还可以约束形参为某一特定类型,如数组,再通过泛型来约束形参的具体类型(字符串数组等)
function show<t>(para: t[]): number {
return para.length;
}
show<string | number>([1, 2, 3, "4"]) // 4
4、泛型结合类的使用
泛型可以用来约束函数,自然也可以用来约束类。泛型结合类的使用,使得可以更加方便地管理特定类型的数据
type userType = { name: string; age: number };
class collection<T extends userType> {
// 约束构造函数的传值类型必须为userType的结构
data: T[];
constructor(...args: T[]) {
this.data = args;
}
showName() {
const arr: string[] = [];
for (const item of this.data) {
arr.push(item.name);
}
return arr;
}
showAge() {
const arr: number[] = [];
for (const item of this.data) {
arr.push(item.age);
}
return arr;
}
}
let hqh: userType = { name: "hqh", age: 21 };
let jxy: userType = { name: "jxy", age: 21 };
let collectionUser = new collection(hqh, jxy);
console.log(collectionUser.showName());
console.log(collectionUser.showAge());
5、public、protected和private
public允许所有实例对象使用protected仅允许构造函数本身及其子类使用private仅允许构造函数本身使用
6、接口
接口interface和类型type都可以用来约束类型
// 接口中也可以动态设置类型
interface article<lockType, cType> {
title: string;
detail: string;
isLock: lockType;
comments: cType[];
}
interface commentsType {
userId: string | number;
content: string;
}
// 动态地将article中的isLock属性设置为boolean类型
let articleA: article<boolean, commentsType> = {
title: "月亮与六便士",
detail: "这是一本非常优美的书",
isLock: false,
comments: [
{
userId: 1212,
content: "这真是一本好书!",
},
{
userId: "我是好人",
content: "这本书太好看了!",
},
],
};
7、只读属性readonly
class axios {
readonly site: string = "https://www.baidu.com";
/*
protected | private readonly site:string = "https..."
如果为readonly属性加上protected或private的话,实例化对象就不能进行访问
*/
constructor(site?: string) {
/*
在构造函数中,readonly的属性是可以被修改值的
这里是如果实例化对象时传值了,则取传的值,否则取默认值
*/
this.site = site || this.site;
}
get() {
return this.site;
}
}
let Axios = new axios("https://www.sina.com");
// 此时site属性是无法被修改的,只允许读取
Axios.site='123' // error
8、构造函数在TS中的使用
class User {
/*
如果不使用`public name: string`方法定义的话就需要:
name: string
constructor(name:string) {
this.name = this.completeName(name);
}
*/
constructor(public name: string) {
// 在构造函数内部可以使用实例方法
this.name = this.completeName(name);
}
completeName(name): string {
return `${name} -- 这是一个帅哥`;
}
}
使用type和interface约束类
1、单例模式
有些情况下(如网络请求方法对象),可能只需要构造函数生产出一个实例对象
class Axios {
private static instance: Axios | null = null;
private constructor(private site: string = "https://www.baidu.com") {
this.site = this.site;
console.log("创建了一个Axios实例");
}
static createAxios(site: string): Axios {
if (Axios.instance == null) {
Axios.instance = new Axios(site);
}
// 这样每次调用都只会将已经缓存的实例对象返回,就不会重复创建消耗内存
return Axios.instance;
}
}
let requestObj = Axios.createAxios("https://www.sina.com");
// 这种模式适合应用于仅需要一个请求地址的场景中
2、抽象类约束子类属性
当需要子类中都具有相同的属性时,可以使用抽象类对子类进行约束
abstract class animation {
// 抽象属性和方法,可以没有,但是如果要使用必须添加
// 且抽象类不能被实例化
abstract name: string;
abstract move(): void;
protected getPos(): { x: number; y: number } {
return { x: 100, y: 200 };
}
}
class player extends animation {
constructor() {
super();
}
name: string = "玩家";
move(): void {
console.log(`${this.name}向X轴移动了${super.getPos()["x"]}米,向Y轴移动了${super.getPos()["y"]}米`);
}
}
class enemy extends animation {
name: string = "敌方坦克";
move(): void {
console.log(`${this.name}移动了`);
}
}
3、抽象类+接口约束类
抽象类可以用来约束子类的属性和方法,但是如果所有约束都加到抽象类中就会很臃肿,因此可以使用抽象类+接口的方式来约束子类
interface AnimationInterface{
name: string
move():void
}
abstract class animation {
protected getPos(): { x: number; y: number } {
return { x: 100, y: 200 };
}
}
// 使用`implements`关键字即可使用接口,可以同时使用多个接口约束
class player extends animation implements AnimationInterface {
constructor() {
super();
}
name: string = "玩家";
move(): void {
console.log(`${this.name}向X轴移动了${super.getPos()["x"]}米,向Y轴移动了${super.getPos()["y"]}米`);
}
}
class enemy extends animation implements AnimationInterface {
name: string = "敌方坦克";
move(): void {
console.log(`${this.name}移动了`);
}
}
4、接口约束对象
interface objInterface {
name: string;
age?: number;
info?(): void;
// 允许添加多个`key`为string类型,`value`为any类型的值
[key: string]: any;
}
const person: objInterface = {
name: "hqh",
school: "华广",
class: "网工一班",
};
5、enum枚举配合接口和数组
enum chooseSex {
boy,
girl,
}
interface userInfo {
name: string;
age: number;
// sex属性的值只允许从枚举对象中选择
sex: chooseSex;
}
const hqh: userInfo = {
name: "hqh",
age: 21,
sex: chooseSex.boy,
};
const jxy: userInfo = {
name: "jxy",
age: 21,
sex: chooseSex.girl,
};
const userList: userInfo[] = [hqh, jxy];
6、接口约束箭头函数
interface show{
(name:string,age:number):string
}
const showName:show=(name:string,age:number):string=>`${name}-${age}`
7、接口合并
TS中,只需要将接口重命名,就可以实现接口合并
interface UserInfo{
name:string
}
interface UserInfo {
school: string;
showStudentId(studentName: string): string;
}
const student:UserInfo={
name: "hqh",
school: "GCU",
showStudentId: function (studentName: string): string {
return studentName
},
}
8、interface和type
不同点
-
interface可以直接通过重命名来合并,type需要 通过&操作符合并interface user{ name:string } interface user{ age:number } type name={ name:string } type age={ age:number } type user= name & age // 如果同时声明两个重名type,先声明的将会被覆盖 type user={ name:string } // 被覆盖 type user={ age:number } -
type可以直接对联合类型起别名,interface只能对属性声明联合类型interface UserInfo { name: string| number; } type UserType = string | number; -
interface和type都可以继承interface user{ name:string } interface userAge extends user{ age:number } type user={ name:stirng } type userAge ={ age:number } & user // interface 继承 type type user={ name:string } interface userAge extends user { age:number } // type继承interface interface user{ name:string } type userAge = { age:number } & user -
type可以用typeof获取类型let UserName:string type UserType = typeof UserName -
type可以声明元组
type ArrayType = [ string , number , boolean ] // 每个位置只能填入特定类型的值
6.type可以结合三元表达式和泛型进行赋值类型
type userType<t> = t extends string ? string : number
装饰器
1. 类装饰器
- 配置
使用装饰器,首先需要在tsconfig.json文件中打开"experimentalDecorators"和"emitDecoratorMetadata"配置以确保装饰器被引擎解析
类装饰器基本使用
装饰器本质其实是函数,可以为所修饰的类添加属性
const myDecorate = (target: Function) => {
target.prototype.getPos = (posiObj: { add: string; meter: number }) => {
console.log(`当前的位置是${posiObj.add}的${posiObj.meter}米处`);
};
};
@myDecorate
class person {
public getPos(posiObj: { add: string; meter: number }) {}
}
let hqh = new person();
hqh.getPos({ add: "佛山", meter: 2000 });
/*
还可以这样写
但是下面的写法,将不会校验getPOs方法中形参的格式,不建议使用
*/
@myDecorate
class person {
public getPos() {}
}
let hqh = new person();
(hqh as any).getPos({ add: "佛山", meter: 2000 });
装饰器也可以叠加使用
const myDecorate: ClassDecorator = (target: Function) => {
...
};
const sucessDecorate: ClassDecorator = (target: Function) => {
target.prototype.successLog = (msg: string) => {
console.log(msg);
};
};
@myDecorate
@sucessDecorate
class person {
// 如果不声明则提示错误,但是不影响使用
successLog: Function;
public getPos(posiObj: { add: string; meter: number }) {}
public requestSuccess() {
this.successLog("获取地址操作成功");
}
}
类装饰器工厂
function myDecorateFac(type: string): ClassDecorator {
switch (type) {
case "学校":
return (target: Function) => {
target.prototype.showSchoolName = (): string => "GCU";
};
break;
case "公司":
return (target: Function) => {
target.prototype.showCompanyName = (): string => "Tencent";
};
break;
default:
return (target: Function) => {
target.prototype.nothing = (): string => "没有信息";
};
}
}
2、函数装饰器
-
基本使用
const myFncDecorate: MethodDecorator = ( target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor, // 也可以写成`descriptor: TypedPropertyDescriptor<any>`,一样的结果 ) => { descriptor.value = (): void => { console.log("这是函数装饰器修改后的结果"); }; }; class show { @myFncDecorate public showMsg(params: string): void { console.log(params); } } let me = new show(); me.showMsg("这是原始方法输出的结果"); -
利用
descriptor参数对方法和静态方法做限制// 在默认情况下,由构造函数创建出来的实例方法或者静态方法都是可以修改的 class show { public showMsg(params: string): void { console.log(params); } public static showName(): void { console.log("这是默认静态方法"); } } let me = new show(); me.showMsg = (): void => { console.log("这是修改后的showMsg方法"); }; show.showName = (): void => { console.log("这是修改后的静态方法"); }; me.showMsg("12"); // 这是修改后的showMsg方法 show.showName(); // 这是修改后的静态方法 // 利用装饰器的descriptor参数,可以修改方法为可读属性 const myFncDecorate: MethodDecorator = ( target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor, ) => { descriptor.writable = false; }; class show { @myFncDecorate public showMsg(params: string): void { console.log(params); } public static showName(): void { console.log("这是默认静态方法"); } } let me = new show(); me.showMsg = (): void => { // error console.log("这是修改后的showMsg方法"); }; show.showName = (): void => { // error console.log("这是修改后的静态方法"); };
3、装饰器实现内容高亮
在页面中实现按键高亮,首先需要获取内容,然后根据内容创建新的DOM节点,最后替换原来的节点
<body>
<!-- 要加上defer属性,确保DOM解析完毕后执行JS脚本 -->
<script defer src="./highlight.js"></script>
<div id="value-box">这是需要高亮的div</div>
<button onclick="changeDiv()">开始替换</button>
</body>
<script lang='ts'>
const myNewDecorate: MethodDecorator = (
arget: Object,
propertyKey: string | symbol,
descriptor: TypedPropertyDescriptor<any>,
) => {
const method = descriptor.value;
const targetDiv = document.querySelector("#value-box") as HTMLDivElement;
const resDiv = document.createElement("div");
resDiv.innerHTML = method();
resDiv.style.color = "red";
resDiv.id = "value-box";
descriptor.value = () => {
targetDiv.replaceWith(resDiv);
};
};
class changeDic {
@myNewDecorate
public static getDivValue() {
let value = document.getElementById("value-box")?.innerHTML;
return value;
}
}
function changeDiv() {
changeDic.getDivValue();
}
</script>
装饰器小tips
装饰器会在DOM节点加载之前执行一次,提前创建出其中的变量以及方法的重写(重写后的方法第一次不会执行),如果包含对DOM节点的操作就会失败,因此需要为JS脚本加上defer属性确保DOM解析完成才执行脚本
4. 延时装饰器
在某些情况下需要装饰器延迟执行,这时候可以使用工厂装饰器来实现可复用的装饰器
const sleepDecorate =
(time: number): MethodDecorator =>
(...args: any[]) => {
const [, , descriptor] = args;
const method = descriptor.value;
descriptor.value = () => {
setTimeout(() => {
method();
}, time);
};
};
class printTimeAfterTime {
@sleepDecorate(2000)
public static getTime() {
let date = new Date().toLocaleString();
}
}
printTimeAfterTime.getTime();
还是装饰器
1、全局错误装饰器
当需要定制错误信息时,可以通过全局错误装饰器来实现
const errorDecorate: MethodDecorator = function (
target: Object,
propertyKey: string | symbol,
descriptor: PropertyDescriptor,
) {
const method = descriptor.value;
descriptor.value = () => {
try {
method();
} catch (error: any) {
console.log(`%c出现错误!`, "color:red;font-size:30px");
console.log(`%c${error.message}`, "color:blue;font-size:26px");
}
};
};
class RequestObj {
@errorDecorate
get() {
throw new Error("请求失败!");
}
}
2、全局装饰器工厂(进阶,可定制版)
const ErrorDecorate =
(title: string = "出现错误!", color: string = "red", fontSize: number = 20): MethodDecorator =>
(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
const method = descriptor.value;
descriptor.value = () => {
try {
method();
} catch (error: any) {
console.log(`%c${title}`, `color:${color};font-size:${fontSize}px`);
console.log(`%c${error.message}`, `color:blue;font-size:26px`);
}
};
};
class RequestObj {
@ErrorDecorate("这是自定义的错误提示", "#111111", 30)
get() {
throw new Error("请求失败!");
}
}
3、检测用户是否登录
const userState = {
userName: "hqh",
isLogin: false,
};
const AuthorizeArticle: MethodDecorator = (
target: Object,
propertyKey: string | symbol,
descriptor: PropertyDescriptor,
) => {
const method = descriptor.value;
if (userState.isLogin) {
return method();
}
alert("请登录后操作");
location.href = "login.html";
};
class ArticleControl {
@AuthorizeArticle
ShowArticle() {
console.log("展示文章");
}
@AuthorizeArticle
StoreArticle() {
console.log("保存文章");
}
}
4、管理用户权限
type UserType = {
userName: string;
isLogin: boolean;
userPermission: string[];
};
const userState: UserType = {
userName: "hqh",
isLogin: true,
userPermission: ["store"],
};
const AuthorizeArticle =
(permission: string[]): MethodDecorator =>
(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
const method = descriptor.value;
const validate = () =>
permission.every(key => {
return userState.userPermission.includes(key);
});
descriptor.value = () => {
if (userState.isLogin === true) {
if (validate()) {
return method();
} else {
alert("权限不足,请联系管理员");
return;
}
} else {
alert("请登录后操作");
location.href = "login.html";
}
};
};
class ArticleControl {
@AuthorizeArticle(["show"])
ShowArticle() {
console.log("展示文章");
}
@AuthorizeArticle(["store", "manage"])
StoreArticle() {
console.log("保存文章");
}
}
5、装饰器模拟网络请求后调用方法执行
interface info {
name: string;
id: number;
}
const requestDecorate =
(url: string): MethodDecorator =>
(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
const method = descriptor.value;
// 模拟网络请求后返回的promise
new Promise<info[]>(resolve => {
setTimeout(() => {
resolve([
{ name: "hqh", id: 1212 },
{ name: "jxy", id: 121212 },
]);
}, 1000);
}).then(value => {
method(value);
});
};
class getUserInfo {
@requestDecorate("https://www.baidu.com")
private get(value: info[]) {
value.forEach(item => {
console.log(item.name);
});
}
}
6、属性装饰器
使用属性装饰器,动态地把属性变为key:value格式
const propertyDecorate: PropertyDecorator = (target: Object, propertyKey: string | symbol) => {
let value: string;
Object.defineProperty(target, propertyKey, {
get() {
return value;
},
set(v: string) {
this.value = `${propertyKey as string}:${v}`;
},
});
};
class propertyClass {
@propertyDecorate
name: string;
constructor(parameters: string) {
this.name = parameters;
}
}
随机产生一个十六进制颜色,并赋值给属性
function getRandomColor() {
var str = "#";
var arr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"];
for (var i = 0; i < 6; i++) {
var num: number = parseInt((Math.random() * 16).toString());
str += arr[num];
}
return str;
}
const colorDecorate: PropertyDecorator = (target: object, key: string | symbol) => {
var color = getRandomColor();
Object.defineProperty(target, key, {
get() {
return color;
},
});
};
class colorDiv {
@colorDecorate
public color: string;
colorfulDiv() {
document.body.insertAdjacentHTML(
"beforeend",
`<div style="background:${this.color}">这是一个div</div>`,
);
}
}
7、使用reflect-metadata验证参数
reflect-metadata相当于为参数添加了一个标记属性,而这个标记属性可以通过重写后的Reflect中的Reflect.getMetadata来获取
import "reflect-metadata";
const paramDecorate: ParameterDecorator = (
target: Object, // 构造函数或实例对象
propertyKey: string | symbol, // 方法名
parameterIndex: number, // 需要标记的形参下标
) => {
let requiredParamIndexArr: number[] = [];
requiredParamIndexArr.push(parameterIndex);
Reflect.defineMetadata("required", requiredParamIndexArr, target, propertyKey);
};
const methodDecorate: MethodDecorator = (
target: Object,
propertyKey: string | symbol,
descriptor: PropertyDescriptor,
) => {
const method = descriptor.value;
descriptor.value = function () {
const requiredArr = Reflect.getMetadata("required", target, propertyKey) || [];
let keyIndex: number;
if (
requiredArr.some((item: number) => {
return (
(item > arguments.length && (keyIndex = item)) ||
(arguments[item] == undefined && (keyIndex = item))
);
})
) {
console.error(`第${keyIndex + 1}个参数没有填写,请完整填写参数!`);
return;
}
method(...arguments);
};
};
class paramTest {
@methodDecorate
showMsg(title: string, content: string, @paramDecorate index: number) {
console.log(`${title} -- ${content} -- ${index}`);
}
}
以上是我个人在TS学习过程中的笔记,如果有错误的地方恳请大佬指出,磕头了咚咚咚
笔记还有很多没有完善的地方,如泛型的工具类型:in、keyof等等,如果有很不幸看到这里的朋友(狗头),可以到大佬的文章《一份不可多得的 TS 学习指南》洗洗眼 :)
PS:推荐一位我学习JS和TS的老师向军大叔,老师的JS课程非常详细,也适合新手学习(不是广告),建议如果是对JS不是特别熟悉的朋友先过一遍JS的课程再学习TS,会轻松很多
还有就是一个帮助TS学习的训练场:TS类型体操。强烈建议在学习TS的过程中,每天刷几题(附上掘金大佬的答案集),对加深TS类型印象非常有帮助