TS —— 1、定义、泛型、类、枚举、元组、抽象
目录
42、TypeScript
(1)JavaScript 与 TypeScript 的区别
(2)优势、缺点
(4)安装
(5)查看版本
(6)编译
(7)写法
(8)为什么要用到TS
(9)定义
1.类型定义
(1)联合类型
(2)任意类型
2.数组类型
(1)方式一:数组
(2)方式二:泛型
3.面向对象—接口类型
(1)接口的定义:
(2)可选属性:
(3)任意属性 :(一个接口允许随便加)
(4)泛型(常用)
4.函数类型
(1)参数默认值
(2)可选参数
(3)接口在函数中的运用
(4)注意:length
(10)泛型
1.泛型类
2.什么时候需要定义泛型函数
3.泛型约束
(1)接口(常用)
(2)数组
(3)类
(4)多个类型参数
(11)类型别名
(12)类
1.定义类
(1)ES5(构造函数)
(2)ES6
2.类的继承
3.修饰符
4.类的类型
5.类实现接口
6.一个类可以实现多个接口
(13)枚举
(14)元组
(15)抽象类abstract
42、TypeScript
TypeScript是.ts文件,与.js相似,但只是用来编写代码,运行还是在.js中(下面优势与缺点)
TypeScript 是一种由微软开发的自由开源的编程语言,他是JavaScript的一个超集,扩展了JavaScript的 语法,主要提供了类型系统和对 ES6 的支持。
TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器上。
(1)JavaScript 与 TypeScript 的区别
TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与
TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。
TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译。
(2)优势、缺点
优点:
强大的IDE支持:体现在三个特性上:
1.类型检查,在TS中允许你为变量指定类型(js文件不会)
2.语法提示(js文件不会)
3.重构Angular2、vue3的开发语言
//分别在两个文件中
缺点:
有一定的学习成本,需要理解
接口(Interfaces)、
泛型(Generics)、
类(Classes)、
枚举类型(Enums)等前端开发可能不是很熟悉的知识点
(3)编辑器
TypeScript 最大的优势之一便是增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等。
主流的编辑器都支持 TypeScript,推荐使用 Visual Studio Code。
获取其他编辑器或 IDE 对 TypeScript 的支持:
Sublime Text
Atom
WebStorm
Vim
Emacs
Eclipse
Visual Studio 2015
Visual Studio 2013
(4)安装
npm install -g typescript
以上命令会在全局环境下安装 tsc 命令,安装完成之后,我们就可以在任何地方执行 tsc 命令了
(5)查看版本
tsc -v
(6)编译
编译一个 TypeScript 文件
tsc hello.ts
使用 TypeScript 编写的文件以 .ts 为后缀
(7)写法
使用 :**(冒号)指定变量的类型,:** 的前后有没有空格都可以
也就是说 :**(冒号)**后面的是类型
let num:number = 15;
num(变量名):number(类型) = 15(具体值)
// 表示定义一个变量num,指定类型为number;
let str:string = 'abc';
// 表示定义一个变量str,指定类型为string;
//在.ts文件中这样写不会报错
//自动生成一个同名的.js文件
(8)为什么要用到TS
//定义一个函数计算二个数据的合计
function sum(x, y) {
if (typeof x != 'number') { //对于形参的类型要添加转换
x = parseInt(x);
}
return x + y
};
sum('1', 2); //3
//TS的方式,直接约束了类型
(9)定义
1.类型定义
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;
(1)联合类型
表示取值可以为多种类型中的一种
let a4: string | number; //a4为多个类型
a4 = 'seven';
a4 = 7;
//提示错误(布尔类型)
function getLength(str: string | number): number { //第二个number是返回类型
return str.length; //length提示错误,为什么?
}
console.log(getLength(123));
//当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,只能访问此联合类型的所有类型里共有的属性或方法
===================================================================================
//解决
function getLength(str: string | number[]): number {
return str.length;
}
console.log(getLength([1, 2, 3]));
(2)任意类型
如果是一个普通类型,在赋值过程中改变类型是不被允许的,任意值(Any)用来表示允许赋值为任意类型
let a1: string = 'seven';
a1 = 7; //提示错误
//但如果是 any 类型,则允许被赋值为任意类型
let a2: any = 'seven';
a2 = 7;
-----------------------------------------------------------------------------------
//变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型
let a3;
a3 = 'seven';
a3 = 7;
//相当于
let a3: any;
a3 = 'seven';
a3 = 7;
2.数组类型
(1)方式一:数组
在 TypeScript 中,数组类型有多种定义方式,比较灵活。
最简单的方法是使用 [类型 + 方括号] 来表示数组:
let arr: number[] = [1, 2, 3, 4, 5];
// 数组的项中不允许出现其他的类型
var arr2: number[] | string[] = [1, '2', 3, 4, 'a'];
// 其它类型的数组
let arr3: any[] = [1, '1', 2, 'x', {id:1},[1,2,3],true];
(2)方式二:泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
泛型变量
let arr:Array<number> =[1,2,3];
let arr:Array<number | string> =['1',2,3]; //定义多个类型
3.面向对象—接口类型
在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象
接口(Interfaces)可以用于对「对象的形状(Shape)」进行描述。
(1)接口的定义:
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 18
};
//上面的例子中,我们定义了一个接口 Person,接着定义了一个变量 tom,它的类型是 Person
//这样,我们就约束了 tom 的形状必须和接口 Person 一致
定义的变量比接口多、少一个属性是不允许的:
let tom2: Person = {
name: 'Tom'
};
let tom3: Person = {
name: 'Tom',
age: 25,
sex: '男' //提示错误
};
(2)可选属性:
interface Person2 {
name: string;
age?: number; //可有可无
}
let tom4: Person2 = {
name: 'Tom' //不会报错
};
// 可选属性的含义是该属性可以不存在。这时仍然不允许添加未定义的属性:
let tom5: Person2 = {
name: 'Tom',
age: 25,
sex: '男' //提示错误
};
(3)任意属性 :(一个接口允许随便加)
interface Person3 {
name: string;
age?: number;
[aa: string]: any; //键名可以为任意类型
};
let tom6: Person3 = {
name: 'Tom',
//随便加
sex: '男',
fun: function(){ },
o:{id: 1},
};
//一旦定义了任意属性,那么确定属性和可选属性都必须是它的子属性
(4)泛型(常用)
判断abc中是否包含a:
方式一:
方式二:简化(推荐)
方式三:
4.函数类型
一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到
//xy为输入的类型,:number为输出类型(number也可以写成void无返回类型)
function sum1(x:number, y:number): number{
return x+y;
}
(1)参数默认值
function sum3(x:number =5, y:number): number{
return x+y;
}
let s1 = sum3(1, 2);
(2)可选参数
function sum4(x: number, y?: number): number[]{ //?必须写在后面
return [x, y]
}
let s2 = sum4(1); //写一个会报错,?可以解决
(3)接口在函数中的运用
//函数方式
function f1(obj: {id: number, name: string}): number {
return obj.id
}
var o = {id: 2, name: 'xyz'}
f1(o)
-----------------------------------------------------------------------------------
//接口方式
interface ObjName{
id: number
name: string
}
function f2(obj: ObjName): number{
return obj.id
}
(4)注意:length
//length(长度)
解决:
===================================================================================
//length可以是任何类型
===================================================================================
function f4<T>(arg: T): T {
console.log(arg.length); //错误: T不存在length属性 比如数值等
} //length可以为任何类型
使用了 extends 约束了泛型 T 必须符合接口 LengthN 的形状,也就是必须包含 length 属性。
interface LengthN {
length: number;
}
function myHello<T extends LengthN>(arg: T): T {
console.log(arg.length);
return arg;
}
myHello <string>('123');
myHello(123); //错误(必须是字符串)
myHello<number>(123); //错误,只能写字符串类型(唯一写法?)
myHello<boolean>(true); //错误
(10)泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定
类型的一种特性。
泛型变量
1.泛型类
// 函数声明
function mySum<T>(x: T): T {
return x;
}
// 函数表达式
let mySum1 = function <U>(x: U): U { //U和T一样
return x;
};
// ES6箭头函数
let mySum2 = <T>(x:T):T => x;
2.什么时候需要定义泛型函数
要创建一个可重用的组件,其中的数据类型就必须要兼容很多的类型,那么如何兼容呢?
function f(a: number, b: number): number[] {
return [a, b]
}
f(1, 2);
function f2(a: string, b: string): string[] {
return [a, b]
}
f2('1', '3')
function f2(a: boolean, b: boolean): boolean[] {
return [a, b]
}
//-----------------------------------------------------------------------------------
// 为了解决上面返回不同类型的问题:
// 泛型的定义
function f3<T>(a:T, b:T): T[] {
return [a, b]
}
f3<number>(1, 2)
f3<string | number>(2, 'a')
f3(1, 2) //类型推断(不建议用,返回值不确定)
f3('a','a')
f3(1,'a') //报错
// 我们把f3这个函数叫做泛型,因为它适用于所有类型,并且不会有any类型存在的问题
// 使用‘类型变量’ 一种特殊的变量,代表的是类型而非值
一旦我们定义了泛型函数,有两种方法可以使用。
第一种就是传入所有的参数,包括类型参数
f3<number>(1, 2)
f3<string | number>(2, 'a')
第二种是最常见的。我们使用/类型推断/ 编译器会根据传入的参数自动地帮助我们确定T的类型
f3(1, 2) //类型推断(不报错,自动)不建议用,返回值不确定
f3('a','a')
f3(1,'a') //报错
//报错
//如果返回类型是布尔,改一下返回类型即可
3.泛型约束
(1)接口(常用)
当你开始使用泛型,你可能会注意到当你创建一个类似”f4”的泛型函数,编译器会强制要求你在函数中正确的使用这些通用类型参数。
function f4<T>(arg: T): T {
console.log(arg.length); //错误: T不存在length属性 比如数值等
}
使用了 extends 约束了泛型 T 必须符合接口 LengthN 的形状,也就是必须包含 length 属性。
interface LengthN {
length: number;
}
function myHello<T extends LengthN>(arg: T): T {
console.log(arg.length); //3(长度)
return arg;
}
myHello<string>('123'); //"123"
myHello(123); //错误(必须是字符串)
=====================================================================
之前上面写过接口泛型,看一下:
方式一:
方式二:简化(推荐)
方式三:
(2)数组
let arr: Array<number> = \[1, 1, 2, 3, 5\];
这段代码编译不会报错,但是一个显而易见的缺陷是,返回值的类型不确定
案例:
function f(length: number, value: any): Array<any> {
let result = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
f(3, 'x'); //["x", "x", "x"] 3个x
在函数名后添加了,其中T用来指代任意输入的类型
简化:(更加灵活)
function f<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
f<string>(3, 'x'); //["x", "x", "x"] 3个x
(3)类
class A2<T>{
n: T;
constructor(num: T) {
this.n = num;
}
add(x: T): T {
return x;
}
}
var a2 = new A2 <number>(1);
a2.add(3)
(4)多个类型参数
function multi<N, S>(sum:[N,S]): [S,N] {
return [sum[1], sum[0]];
}
multi <number, string>([3, 'one']); //["one", 3]
===================================================================================
//案例:
//泛型约束
interface Length3{
length: number;
}
interface createA3<N, T extends Length3> {
(a: N, b: T): Array<T>
}
var c3: createA3<number, string>;
c3 = function <N, T>(i: N, v: T): Array<T> {
var a: T[] = [];
return a;
};
c3(2, '123');
(11)类型别名
function myHello(aa: n) {
return 'Hello,' + aa;
};
type n = number;
let name: n = 18;
console.log(myHello(name));
(12)类
传统方法中,JavaScript 通过构造函数实现类的概念,通过原型链实现继承。
类(Class):定义了一件事物的抽象特点,包含它的属性和方法
1.定义类
(1)ES5(构造函数)
// JavaScript 语言中,生成实例对象的传统方法是通过构造函数
function Cat(name, color) { //构造函数
this.name = name;
this.color = color;
//this.type='动物';
//this.eat = function(){console.log("吃老鼠")};
};
// 原型中
Cat.prototype.type = '动物';
Cat.prototype.eat = function () {
return console.log("吃老鼠");
};
var c1 = new Cat("大明", "黄色");
var c2 = new Cat("小明", "白色");
(2)ES6
ES6 的类,完全可以看作构造函数的另一种写法。
注意,定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以
了
另外,方法之间不需要逗号分隔,加了会报错。
class Cat2 {
name: string; //值类型
color: string; //定义值类型
constructor(name, color) {
this.name = name;
this.color = color;
}
eat() {
return console.log("吃老鼠");
}
sayName() {
return `My name is ${this.name}`;
}
}
var c3 = new Cat2("小小明", "黑色");
console.log(c3.eat())
console.log(c3.sayName())
==================================== 编译后 ========================================
var Cat2 = /** @class */ (function () {
function Cat2(name, color) {
this.name = name;
this.color = color;
}
Cat2.prototype.eat = function () {
return console.log('吃老鼠');
};
Cat2.prototype.aa = function () {
return "you " + this.name;
};
return Cat2;
}());
var c3 = new Cat2("小小米", "黑色");
console.log(c3.eat());
console.log(c3.aa());
2.类的继承
class Animal {
name: string;
constructor(name) {
this.name = name;
}
eat() {
return "吃骨头";
}
}
//继承
class Dog extends Animal {
age: string;
aa: string;
constructor(name, age, aa) {
super(name)
this.age = age;
this.aa = aa;
}
sayHi() {
return this.name + ',' + this.eat(); //调用父类的
}
}
let d = new Dog('a', 'a', 'a');
console.log(d.sayHi());
3.修饰符
public 属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的;
protected 属性或方法是受保护的,它和 private类似,区别是它能在子类中允许被访问的;
private 属性或方法是私有的,不能在声明它的类的外部访问;
protected:
//常见写法
class Obj3 {
private name;
public constructor(name) {
this.name = name;
}
protected action() {
return this.name
}
};
class Dog2 extends Obj3 {
a: string;
b: string;
c: string;
constructor(name, a, b, c) {
super(name);
this.a = a;
this.b = b;
this.c = c;
}
say() {
//return this.name //调用的父类
return this.action()
}
};
let obj3 = new Obj3('tom');
//obj3.name;
//obj3.action();
let d2 = new Dog2('abc', 'a', 'b', 'c');
//static不需要实例化,直接调用
4.类的类型
class Animal5 {
name: string;
constructor(name: string) {
this.name = name;
}
sayHi(): string {
return `My name is ${this.name}`;
}
}
let s4: Animal5 = new Animal5('Jack');
console.log(s4.sayHi());
==================================== 编译后 ========================================
var Animal5 = (function () {
function Animal5(name) {
this.name = name;
}
Animal5.prototype.sayHi = function () {
return "My name is " + this.name;
};
return Animal5;
}());
var s4 = new Animal5('Jack');
console.log(s4.sayHi()); //My name is Jack
5.类实现接口
interface Obbj4 {
name: string; //子类接了接口,属性和方法都必须写
action(): string;
}
-----------------------------------------------------------------------------------
//写法一
class dog2 implements Obbj4 {
name: string;
constructor(name) {
this.name = name;
}
action() {
return '111'
}
}
let s6 = new dog2('Jack');
-----------------------------------------------------------------------------------
//写法二
//接口的约束(注意name后面的逗号)
实现(implements)是面向对象中的一个重要概念。一般来讲,一个类只能继承自另一个类,
有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),
用 implements 关键字来实现。这个特性大大提高了面向对象的灵活性。
举例来说,门是一个类,防盗门是门的子类。如果防盗门有一个报警器的功能,
我们可以简单的给防盗门添加一个报警方法。这时候如果有另一个类,车,也有报警器的功能,
就可以考虑把报警器提取出来,作为一个接口,防盗门和车都去实现它:
interface Alarm { // 报警器
sing(); //一个抽象的空方法
};
class Door { }; // 定义门
// 防盗门继承门实现报警器的功能
class SecurityDoor extends Door implements Alarm {
sing() {
console.log('SecurityDoor sing');
}
};
// 车实现报警器的功能
class Car implements Alarm {
sing() {
console.log('Car sing');
}
};
var d1 = new SecurityDoor();
var car = new Car();
6.一个类可以实现多个接口
interface Alarm2 {
alert();
}
interface Light {
lightOn();
lightOff();
}
-----------------------------------------------------------------------------------
// 实现多个接口Car实现了Alarm和Light接口,既能报警,也能开关车灯
class Car3 implements Alarm2, Light {
alert() {
console.log('Car alert');
}
lightOn() {
console.log('Car light on');
}
lightOff() {
console.log('Car light off');
}
aaa() {
console.log('aaa');
}
}
-----------------------------------------------------------------------------------
//这种写法只能用一个接口
(13)枚举
数组中获取数据,只能通过数组来获取,不能通过名称来获取
enum类型是对JavaScript标准数据类型的一个补充
var arr = ['a', 'b', 'c'];
arr[0]; //可以
arr['a'] //错误 不能通过名称来获取,只能索引
var obj = {a: 'a', b: 'b'}; //对象
obj.a //'a' 可以
obj['a'] //'a' 可以
定义:
enum Color {Red, Green=5, Blue};
let c = Color.Blue; //6
let c2: Color = Color.Green; //5(元素编号会随之变化)
let c3 = Color[0]; //Red
let c4 = Color[1]; //undefined
let c4: string = Color[0]; //Red
let c5: string = Color[2]; //undefined
任意值
enum Color6 {Red=1.6, Green, Blue=<any>"b"};
let c6: number = Color6.Red; //1.6
let c6: string = Color6.Green;//2.6(元素编号会随之变化)
let c6: number = Color6.Blue; //b
如果未手动赋值的枚举项与手动赋值的重复了后面的会覆盖前面的,尽量不要重复
enum Color7 {Red=1, Green=3, Blue=<any>"b"};
let c7:string = Color7[1]; //Red
let c8:string = Color7[3]; //Green
let c9:string = Color7['b']; //Blue
枚举项有两种类型:常数项和计算所得项
var aa='123';
enum Color8{Red, Green=<any>aa, Blue="blue".length};
let c:Color8 = Color8.Green; //123
let c:Color8 = Color8.Blue; //4
如果紧接在计算所得项后面的是未手动赋值的项,那么它就会因为无法获得初始值而报错
var aa='123';
enum Color9 {Red=<any>aa, Green=<any>aa, Blue="blue".length}; //可以的
//enum Color9 {Red=<any>aa, Green, Blue}; //这种错误
(14)元组
数组合并了相同类型的对象
元组合并了不同类型的对象。
我们知道数组中元素的数据类型都一般是相同的(any[] 类型的数组可以不同),如果存储的元素数据类型不同,则需要使用元组
var lists: number[] = [1, 2, 3];
var lists2: Array<string> = ['a', 'b', 'c']; //数组泛型 不允许有其它的类型
var lists3: Array<string | number> = ['a', 'b', 1, 2];
//任意值
var lists4: any[] = ['a', 1, true];
===================================== 元组 =========================================
let x: [number,string];
x = [5,'abc'];
元组它允许表示一个已知元素数量和类型的数组,各元素的类型不必相同
1、数组中的数据类型必须和规定的类型顺序对应起来
2、当使用越界索引给数组赋值的时候,会使用联合类型(只要值是规定类型的某一种即可)
var ff = function () {
let x1: [string, number];
x1 = ['abc', 5];
x1[1] = 10;
console.log(x1); //["abc", 10]
}
ff();
(15)抽象类abstract
- 抽象类的子类必须实现抽象类里的抽象方式
不能被实例化
abstract class A {
abstract action():void;
}
class B extends A {
action(){ //1.子类必须实现此方法
}
}
var a = new A(); //2.抽象类不能实例化
还没有评论,来说两句吧...