前言
vue3 曾经公布了,ts 的脚步曾经拦截不住了,还只会 es6? 别想了,人家都曾经在口头了,以下是 ts 的根本系列教程,ts 的根本语法,高级语法等,以及在 vue 我的项目中如何利用 ts,跟着我连忙撸起来吧。
根本数据类型
数字
const a: number = 3;
字符串
const b: string = "1";
数组
const c: number[] = [1, 2, 3];
const d: Array<number> = [1, 3];
const arr: any[] = [1, "33", true];
元组
能够为数组中的每个参数定义绝对应的类型
const e: [number, string] = [1, "ww"];
枚举
enum error {
blue = 3,
"orange",
}
const f: error = error.orange;
console.log(f); // 输入 4
tips
- 如果
未赋值
的上一个值是数字
那么这个未赋值的值
的是上一个值的值 +1- 如果
未赋值
的上一个值未赋值
那么输入的就是它的下标
- 如果
未赋值的上一个值的值是非数字
, 那么必须赋值
布尔类型
const g: boolean = true;
对象
const i: object = {};
undefined
罕用于组合类型
let j: number | undefined;
null
let k: null;
void
指定办法类型,示意没有返回值, 办法体中不能return
function aa(): void {console.log(1);
}
// 如果办法有返回值,能够加上返回值的类型
function bb(): number {return 1;}
never
其余类型 (包含 null 和 undefined)的子类型,代表从不会呈现的值
let l: never;
// 匿名函数并抛出异样
l = (() => {throw new Error("111");
})();
任意类型
让参数能够是任何一种类型
let h: any = 1;
h = true;
h = "st";
函数
函数申明
function cc(): void {}
办法传参
function getUserInfo(name: string, age?: number, school: string = "清华大学") {return `name:${name}--age:${age}--school:${school}`;
}
tips: ? 代表这个参数可传可不传, 不传就是 undefined, 也可定义个默认的值
残余参数
传递多个时,如果用了残余参数,就能够把未定义的形参转换为数组。
function sum (a: number, b: number, ...arr: number[]): number {
let sum: number = a + b;
arr.forEach((element) => {sum += element;});
console.log(arr); [3,4,5]
return sum;
}
console.log(sum(1, 2, 3, 4, 5)); //15
函数重载
function reload(name: string): string;
function reload(age: number): string;
function reload(param: any): any {return typeof param === "string" ? ` 我是:${param}` : ` 我的年龄:${param}`;
}
console.log(reload(18)); // 年龄
tips:
被重载
的办法,是没有办法体
,能够依据参数的类型走其中一个办法并判断参数,但如果传入的参数类型不是任何被重载办法的参数类型
就不容许通过。
第 1 个重载(共 2 个),“(name: string): string”,呈现以下谬误。类型“never[]”的参数不能赋给类型“string”的参数。第 2 个重载(共 2 个),“(age: number): string”,呈现以下谬误。类型“never[]”的参数不能赋给类型“number”的参数
类
class Person {
// 公有变量
private name: string;
// 构造函数
constructor(name: string) {this.name = name;}
// 获取名字
getName(): string {return this.name;}
// 设置名字
setName(name: string): void {this.name = name;}
}
let p = new Person("张三");
p.setName("李四");
console.log(p);
继承
class Son extends Person {
// 动态属性
public static age: number = 18;
// 学校
public school: string;
// 构造方法
constructor(name: string, school: string) {
// 拜访派生类的构造函数中的 "this" 前,必须调用 "super", 初始化父类构造函数 -- 并把参数传给父类
super(name);
// 把传进来的 school 赋值给全局变量
this.school = school;
}
// 静态方法
static run(name: string): string {return `${name}在跑步, 他的年龄才 ${this.age}`;
}
}
let son = new Son("王五", "清华大学");
son.setName("赵六"); // 公有类也不能在子类的内部拜访, 但可通过公开的办法中进行赋值和拜访
console.log(son);
console.log(Son.run("方七"));
console.log(Son.age);
tips:
- public 在以后类外面,子类,类里面都能够拜访
- protected 在以后类和子类外部能够拜访,类内部无法访问
- private 在以后类外部可拜访,子类,类内部都无法访问。
- 属性不加修饰符, 默认就是私有的 (public)
多态
通过形象办法 / 办法重载 – 实现多态 – 多态的作用是用来定义规范
// 形象父类
abstract class Animal {
private name: string;
constructor(name: string) {this.name = name;}
// 形象成员 -- 办法
abstract eat(): any;
// 形象成员 -- 属性
protected abstract ages: Number;
sleep(): void {console.log("睡觉");
}
}
class cat extends Animal {
ages: Number = 2;
constructor(name: string) {super(name);
}
// 非抽象类“cat”不会主动实现继承自“Animal”类的形象成员“eat”, 必须手动定义父类中的形象办法 -- 多态
eat(): string {return "猫吃鱼";}
// 多态
sleep(): string {return "猫在睡觉";}
}
console.log(new cat("33").sleep());
tips:
- 抽象类无奈
实例化
。- 非抽象类继承形象父类时
不会主动实现
来自父类的形象成员, 必须手动定义
父类中的形象成员,否则报错。- 形象成员包含
属性
和办法
接口
在面向对象的编程中,接口是一种标准的定义,它定义了行为和动作的标准,
在程序设计外面,接口起到一种限度和标准的作用。
接口定义了某一批类所须要恪守的标准,接口不关怀这些类的外部状态数据,也不关怀这些类里办法的实现细节,它只规定这批类里必须提供某些办法,提供这些办法的类就能够满足理论须要。ts 中的接口相似于 java,同时还减少了更灵便的接口类型,包含属性、函数、可索引和类等。
属性接口
interface InterfaceName {
first: string;
second?: string; // 加个问号,接口属性就能够变成可传可不传了,不传默认是 undefined。}
// 打印变量
function logParam(name: InterfaceName): void {console.log(name.first, name.second, 11);
}
// 定义参数
const obj = {first: "1", second: "fff", three: 1};
//logParam({first: "1", second: "1", three: 1}); // 报错, 只能传接口定义的值
logParam(obj);
tips: 用个变量来存储传入的变量, 这样能够传入定义的接口以外的值,否则如果间接传入对象中无接口定义的值会报错,所以倡议接口定义了哪些值就传哪些值。
函数类型接口
对办法传入的参数类型, 以及返回值类型进行束缚, 可批量进行束缚。
interface keyMap {(key: string, value: string): string;
}
let logKeyMap: keyMap = function (key1: string, value: string): string {return key1 + value;};
console.log(logKeyMap("key1", "value"));
tips: 接口只对传入的参数的类型和参数的个数进行束缚,不对参数名称进行束缚。
可索引接口
- 束缚数组
interface Arr {[index: number]: string;
}
let ss: Arr = ["2121"];
- 束缚对象
interface Obj {[index: string]: string;
}
let interfaceArr: Obj = {aa: "1"};
tips:
- 对
数组
进行束缚,index
后必须跟着number
类型。- 对
对象
进行束缚,index
后必须跟着string
类型- 索引签名参数类型必须为 “string” 或 “number”
类类型接口
- 对
类
进行束缚, 相似抽象类
的实现。
interface Animals {
name: string;
eat(): void;}
class Dogs implements Animals {
name: string;
constructor(name: string) {this.name = name;}
eat() {}
}
- 接口继承 – 接口能够继承接口
interface Dog {eat(): void;
}
interface Persons extends Dog {work(): void;
}
class Cat {code() {console.log("猫在敲代码");
}
}
// 可继承类后再实现接口
class SuperMan extends Cat implements Persons {eat(): void {console.log(1);
}
work(): void {console.log(2);
}
}
let superMan = new SuperMan();
superMan.code();
tips: 类接口会对类的
属性
和办法
进行束缚,相似非抽象类继承抽象类时必须实现某些办法和属性,但对属性和办法的类型的束缚更加严格,除了办法void 类型
可被从新定义
外,其余属性或办法的类型定义须要和接口保持一致。
泛型
软件工程中,咱们不仅要创立统一的定义良好的 api,同时也要思考可重用性。
组件不仅可能反对以后的数据类型,同时也能反对将来的数据类型,这在创立大型零碎时为你提供了非常灵便的性能
泛型就是解决 类
、接口
、 办法
的复用性
,以及对 不特定数据类型
的反对。
要求: 传入的参数和返回的参数统一
函数的泛型
function getDate<T>(value: T): T {return value;}
console.log(getDate<number>(123));
tips: 这里的
T
可改成其余任意值但定义的值,和传入的参数以及返回的参数是一样的, 个别默认写法是 T,也是业内标准的抉择。
类的泛型
class MinClass<T> {public list: T[] = [];
// 增加
add(value: T): void {this.list.push(value);
}
// 求最小值
min(): T {
// 假如这个值最小
let minNum = this.list[0];
for (let i = 0; i < this.list.length; i++) {
// 比拟并获取最小值
minNum = minNum < this.list[i] ? minNum : this.list[i];
}
return minNum;
}
}
// 实例化类 并且指定了类的 T 的类型是 number
let minClass = new MinClass<number>();
minClass.add(23);
minClass.add(5);
minClass.add(2);
console.log(minClass.min());
// 实例化类 并且指定了类的 T 的类型是 string,则其办法的传参和返回都是 string 类型
let minClass2 = new MinClass<string>();
minClass2.add("23");
minClass2.add("5");
minClass2.add("2");
console.log(minClass2.min());
接口的泛型
- 第一种写法
interface ConfigFn {
// 标准参数类型, 返回值类型
<T>(value: T): T;
}
let getData: ConfigFn = function <T>(value: T): T {return value;};
console.log(getData<string>("z11"));
- 第二种写法
interface ConfigFn<T> {
// 参数类型,返回值类型
(value: T): T;
}
// 接口办法
function getData<T>(value: T): T {return value;}
// 应用接口
let myGetDate: ConfigFn<string> = getData;
console.log(myGetDate("3"));
tips: 接口的泛型只针对函数类型的接口
类当做参数传入泛型类
// 用户类 -- 和数据库表字段进行映射
class User {
username: string | undefined;
password: string | undefined;
// 构造函数 - 初始化参数
constructor(param: {
username: string | undefined;
password?: string | undefined;
}) {
this.username = param.username;
this.password = param.password;
}
}
// 数据库类
class Db<T> {add(user: T): boolean {console.log(user);
return true;
}
updated(user: T, id: number): boolean {console.log(user, id);
return true;
}
}
let u = new User({username: "张三",});
//u.username = "李四";
u.password = "111111";
let db = new Db<User>();
db.add(u);
db.updated(u, 1);
tips: 类的参数名和类型都做了束缚。
模块
外部模块称为命名空间,内部模块简称为模块,模块在其本身的作用域里执行,而不是在全局作用域里;
这意味着定义在一个模块里的变量、函数、类等等在模块内部是不可见的,除非你明确的应用 export
模式之一导出它们。
相同,如果想应用其它模块导出的变量,函数,类,接口等的时候,你必须要导人它们,能够应用 import
模式之一。
咱们能够一些公共的性能独自抽离成一个文件作为一个模块。
模块外面的变量、函数、类等默认是公有的,如果咱们要在内部拜访模块外面的数据 (变量、函数、类)
咱们须要通过 export
裸露模块外面的数据 (变量、函数、类 …)。
裸露后咱们通过 import
引入模块就能够应用模块外面裸露的数据(变量、函数、类 …)
//modules/db.ts
function getDate(): any[] {console.log("获取数据");
return [
{userName: "张三",},
{userName: "李四",},
];
}
// 一个模块外面能够用屡次
// export {getDate};
// 一个模块外面只能用一次
export default getDate;
import {getDate as getDbDate} from "./modules/db";
import getDbDate from "./modules/db";
getDbDate();
tips: 这个调试时浏览器中不能间接应用, 可在
node
和weakpack
的环境中调试。
命名空间
在代码量较大的状况下,为了防止各种变量命名相冲突,可将类似性能的函数、类、接口等搁置到命名空间内
TypeScript 的命名空间能够将代码包裹起来,只对外裸露须要在内部拜访的对象。
命名空间和模块的区别
- 命名空间:外部模块,次要用于组织代码,防止命名抵触。
- 模块:ts 内部模块的简称,偏重代码的复用,一个模块里可能会有多个命名空间。
// modules/Animal.ts
export namespace A {
interface Animal {
name: String;
eat(): void;}
export class Dog implements Animal {
name: String;
constructor(theName: string) {this.name = theName;}
eat() {console.log("我是" + this.name);
}
}
}
export namespace B {
interface Animal {
name: String;
eat(): void;}
export class Dog implements Animal {
name: String;
constructor(theName: string) {this.name = theName;}
eat() {}
}
}
import {A, B} from "./modules/Animal";
let ee = new A.Dog("小贝");
ee.eat();
装璜器
- 类装璜器:类装璜器在类申明之前被申明(紧靠着类申明),类装璜器利用于类构造函数,能够用于监督,批改或者替换类定义。
function logClass(params: any) {console.log(params);
//params 就是指代以后类 --HttpClient
params.prototype.apiUrl = "动静扩大属性";
params.prototype.run = function () {console.log("动静扩大办法");
};
params.prototype.getDate = function () {console.log("动静扩大办法 2");
};
}
@logClass
class HttpClient {constructor() {}
getDate() {console.log(1);
}
}
let http: any = new HttpClient();
console.log(http.apiUrl);
http.run();
http.getDate();
tips: 装璜器会笼罩被装璜的类中的办法。
- 装璜器工厂
可传参的装璜器
function logClassB(param: string) {return function (target: any) {console.log(target, "装璜器以下的类");
console.log(param, "装璜器传进来的属性");
};
}
@logClassB("小慧")
class HttpClients {constructor() {}
getDate() {}
}
let https: any = new HttpClients();
console.log(https);
- 构造函数装璜器
function logClassC(target: any) {console.log(target, 1111);
// 用在这里继承指标类并重载办法和属性
return class extends target {
a: any = "我是批改后的属性";
getDate() {console.log(this.a + "-- 装璜器中的办法输入的");
}
};
}
@logClassC
class HttpClient2 {
public a: string | undefined;
constructor() {this.a = "我是构造函数外面的 a";}
getDate() {console.log(this.a);
}
}
const https2 = new HttpClient2();
https2.getDate();
未完待续~
下期预报: 在 vue 中应用 ts。