ts简介:
- ts是什么:ts是js的超集
- 特点:提供类的类型和es6的支持
- 优点:
- 增加代码的可读性和可维护性以及兼容性
- 类型系统是最好的文档
- 在编译阶段就发现错误,比运行时发现错误好
- 增加了编辑器和ide的功能,代码不全、接口提示、跳转到定义、重构
- js文件可重命名为.ts文件
- 不显式的定义类型,也能自动作出类型推论
- 可定义一切类型
- 即使typescript编译报错,也可生成js文件
- 兼容第三方库,即使第三方库不是用ts写的,也可编写单独的类型文件供ts读取
- 缺点:
- 集成到构建流程需要工作量,可能和一些库结合的不是很完美
- 安装:
- npm i -g typescript 执行tsc ts文件来编译会生成js文件或者ide支持
(1)数据类型
数据类型主要作用是:方便数据维护和数据校验
布尔类型 boolean
数字类型 number
字符串类型 string
数组类型 array
元组类型 tuple
枚举类型 enum
任意类型 any
null 和 undefined
void类型
never类型
数组的三种写法:
var arr:number[] = [11,22,33];
console.log(arr);
var arr:Arrary<number> =[11,22,33];
console.log(arr);
var arr:any[] =['1yhuyhub1',22,33,true];
console.log(arr);
枚举类型
字面意思理解就是 单独每一个拿出来 进行举例说明
enum Flag = {success =11; error=2}
let s:Flag = Flag.success;
console.log(s); //11
enum Color = {blue,red,success =1; error=2}
let c:Color = Color.blue;
console.log(c); //1
如果没有类型进行赋值,就是没有赋值,则打印的就是下标;
任意类型
任意类型可以解决很多问题,比如处理元素节点;
如上图:如果使用Object 这样就会报错, 但是如果使用any 就不会出现这样 报错
null和undefined
null 和 undefined是其他类型(never)的子类型;
let num: number;
console.log(num) // undefined
那么 正确使用呢,
let num: number | undefined;
num = 123
console.log(num) // 123
如果没有值的话,可以同时定义一个当前类型和其他的null或者undefined类型
那么 一个元素可能是 number类型 可能是 null 也可能是undefined类型
所以 定义未赋值 或者 定义赋值都不会报错;
viod类型
void表示没有任何类型,一般用于定义方法的时候没有返回值
// 表示方法没有返回任何类型
function par(): void {
console.log('par')
}
par()
有返回值的话,那么就要指定返回值类型
function par(): number {
return 123
}
par()
never类型
never 类型表示的是那些永不存在的值的类型。 例如, never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never 类型,当它们被永不为真的类型保护所约束时。
never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。 即使 any也不可以赋值给never。
var a:never;
a=(()=>{
throw new Error('错误');
})()
(2)ts函数写法
原始的ES6
// 函数类声明
function par(){
return 'par'
}
// 匿名类函数
var par2 = function (){
return 'par2'
}
ts写法:声明函数 和 匿名函数
// 函数声明
function run():string{
return 'ni shi haoren'
}
// 匿名函数
var fun2 = function():string{
return 'ni shi haoren'
}
ts中的默认参数
function getInfo(name:string,age:number=20):string{
if(age){
return `${name}---${age}`
}else{
return `${name}---`
}
}
getInfo('zhansan',9999);
剩余参数
function sum(...result:number[]):number{
let sum = 0;
for(let i=0;i<result.length;i++){
sum+=result[i];
}
return sum;
}
sum(1,2,3,4);
如果说使用多个参数,且包含剩余参数的函数,那么剩余参数必须放到最后面;
ts函数重载
Java中的方法重载,指的是两个或者两个以上同名的函数,但是它们的参数是不一样的,这时候就会出现函数重载;
typescript中的重载,通过一个函数提供多个函数类型定义来实现重载;
ES5中出现同名的方法,下面的会替换上面的方法;
ts实现
// ts中的重载
function gteInfo(name:string):string;
function getInfo(age:number):string;
function getInfo(str:any):any{
if(typeof str === 'string'){
return str
}else {
return str
}
}
console.log(getInfo())
(3) 类
ES5中的类
function Person{
this.name = 'zhansan';
this.age = 20;
}
var p = new Person();
console.log(p.name);
ES5构造函数 和 原型链 里面增加方法
function Person{
this.name = 'zhansan';
this.age = 20;
this.run = function(){
console.log(this.name);
}
}
Person.prototype.sex = 'man';
Person.prototype.work = function(){
console.log(this.name + "在工作");
}
var p = new Person();
p.work();
那么 原型链上面的方法可以被实例共享,但是构造函数的不会;
ES5增加静态方法
function Person{
this.name = 'zhansan';
this.age = 20;
this.run = function(){
console.log(this.name);
}
}
Person.getInfo = function(){
console.log("23456789);
};
// 使用静态方法
Person.getInfo();
(4)继承
ES5继承----对象冒充继承
function Person{
this.name = 'zhansan';
this.age = 20;
this.run = function(){
console.log(this.name);
}
}
Person.prototype.sex = 'man';
Person.prototype.work = function(){
console.log(this.name + "在工作");
}
//定义一个其他方法
function Dog(){
Person.call(this);
}
//使用继承的方法
var p = new Dog();
p.run();
// p.work(); 不可以
继承的实现: 对象冒充可以继承构造函数里面的属性和方法,但是不能继承 原型链的方法;
ES5继承----原型链继承
function Person{
this.name = 'zhansan';
this.age = 20;
this.run = function(){
console.log(this.name);
}
}
Person.prototype.sex = 'man';
Person.prototype.work = function(){
console.log(this.name + "在工作");
}
//定义一个其他方法
function Dog(){
console.log('我是好人’);
}
//使用继承的方法
Dog.prototype = new Person();
var dog = new Dog();
dog.work();
dog.run();
原型链的问题:实例化的时候 没法给父类传参;
ES5继承----原型链+构造函数 继承
function Person{
this.name = 'zhansan';
this.age = 20;
this.run = function(){
console.log(this.name);
}
}
Person.prototype.sex = 'man';
Person.prototype.work = function(){
console.log(this.name + "在工作");
}
//定义一个其他方法
function Dog(name, age){
Person.call(this,name,age);
}
//使用继承的方法
Dog.prototype = new Person();
var dog = new Dog('zhangsan',89);
dog.work();
dog.run();
ts中的类定义
class Person{
name:string;
construct(n:string){ // 实例化的时候会触发construct
this.name = n;
}
run():void{
console.log(this.name);
}
}
var p = new Person('zhansan');
p.run();
ts中的继承
class Person{
name:string;
construct(n:string){ // 实例化的时候会触发construct
this.name = n;
}
run():void{
console.log(this.name);
}
}
class Dog extends Person{
construct(n:string){
super(name); //构造函数和super都要有;super 相当于 调用父类的构造函数
}
}
var p = new Dog('zhansan');
p.run();
(5) 类的修饰符
- public 公有修饰符,可以在类外使用修饰符的属性或行为。
- protected 受保护修饰符,可以在类(子类)内使用修饰符的属性或行为
- private 私有修手符,只可以在当前类(非子类)使用修饰符的属性或行为。
- readonly 将属性设置为只读的,只读的属性不可被修改,只读属性必须在声明时或构造函数里被初始化。
private的使用
class Parson{
protected name:string; // 保护类型
constructor(name:string) {
this.name = name;
}
run():string{
return `$(this.name)在做事情`
}
}
var p = new Parson('哈哈哈')
console.log(p.name)
那么 name 会提示一个编写的错误
(6)静态属性和静态方法
ES5 静态属性 和 静态方法
// 静态属性 静态方法
function Parson() {
this.run = function () { // 实例方法
}
}
Parson.name = '哈哈哈'; // 静态属性
Parson.run2 = function (){ // 静态属性
}
var p = new Parson();
Parson.run2(); // 静态方法的一个调用
静态属性 和 静态方法都是直接绑定在函数上面的,实例属性和实例方法都是在函数内部的;
ts的 静态属性 和 静态方法
class Person{
public name:string;
public age:number = 20;
constructor(name:string){
this.name = name;
}
run(){ // 实例方法
console.log(this.name + "123456");
}
work(){ // 实例方法
console.log(this.name+"098765");
}
static print(){ // 静态方法
console.log(this.name+"098765-"+ this.age);
}
}
var p = new Person();
p.run(); // 使用实例方法
Person.print(); //使用静态方法
- 实例方法 必须在外部实例化以后才能使用;
- 实例方法 前面加上static 就会变成静态方法;
- 静态方法不能使用基本属性,只能使用静态属性;
(7)抽象方法
- 抽象类
一个类要求它的字类必须包含指定方法,它是提供其他类继承的基类,不能被直接实例化。
定义抽象类:
abstract class Animal {
abstract eat():any ;
}
let a=new Animal(); // 报错:无法创建抽象类的实例
- 抽象方法
// 父类
abstract class Animal {
public name: string;
constructor(name: string) {
this.name = name;
}
abstract eat(): any;
}
// 子类Dog
class Dog extends Animal {
constructor(name: string) {
super(name);
}
// 抽象类的子类必须实现抽象类里面的抽象方法
eat() {
console.log(this.name + '在吃肉');
}
}
let d = new Dog('达摩');
d.eat();
// 子类Cat
class Cat extends Animal {
constructor(name: string) {
super(name);
}
}
子类Cat不实现eat()方法,就会报错:非抽象类“Cat”不会实现继承自“Animal”类的抽象成员“eat”,即子类Cat不会自动继承父类的方法
(8)接口
ts中的接口
接口的一种规范的定义,它定义了行为和动作的规范,是一批类所需要遵守的规范,接口不关这些类中的内部状态,不会去关这些类的方法的实现细节,比抽象类型更规范。
接口类型
- 属性接口 (规范数据类型)
- 函数类型接口 (对方法传参数和返回值进行一个约束)
- 索引接口 (数组,对象)
- 类型接口 (对类的一个约束)
定义的方法
function print():void{
console.log('12345678');
}
print();
定义方法(参数的限定)
function print(label:string):void{
console.log('12345678');
}
print();
接口的实现
对批量方法传入参数进行约束;
interface FullName{
first:string, // 接口属性
second:string
}
function name(name:FullName){
console.log(name.first + ''----"+ name.second);
}
// name('23456'); 错误写法
var obj = { //必须传入 first,second
age:20,
first:'zhangsan',
second:'siwu'
}
name(obj);
传入的对象必须包含接口需要实现的参数;
(9)泛型函数
泛型: 可以支持不特定的数据类型; 要求:传入的参数和返回的参数一致;
举例:只能返回string类型
function Parson(value:string):string{
return value
}
方法一:
使用any可以实现,但是相当于放弃了类型检查;
function Parson(value:any):any{
return '哈哈哈';
}
Parson(123);
Parson('hhh')
上面可以返回 string,和 number;
返回类型可以是任意类型实现
function Parson<T>(value:T):any{
return '123';
}
Parson<number>(123);
Parson<string>('这是一个泛型');
将返回值的类型设置成any即可;
(10)泛型类
举例:比如有一个算法,需要同时支持返回数字和返回字符串两种类型,就可以通过范型类来实现;
class Point<T>{
x: T
y: T
z?: T
constructor(x: T,y: T,z?: T) {
this.x = x
this.y = y
this.z = z
}
}
let p1 = new Point(1,2,3);
let p2 = new Point<string>("1","2","3");
let p3: Point<number> = new Point(1,2);
console.log(p1)
console.log(p2)
(11)ts的命名空间
命名空间里面的方法要使用,必须暴露出去;
//命名空间主要目的就是将一个模块内部再进行作用域的划分, 防止一些命名冲突
export namespace Time {
export function format(time: string){
return "2021-11-12"
}
}
export namespace Price {
export function format(price: number) {
return "$15,000"
}
}