TypeScript入门
基本类型和扩展类型
Typescript与Javascript共享相同的基本类型,但有一些额外的类型。
- 元组
Tuple - 枚举
enum Any与Voidnever
基本类型
```
// 数字
let num: number = 6;
let num: number = 0xf00d;
// 字符串
let name: string = "bob";
// 数组,第二种方式是使用数组泛型,Array<元素类型>:
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];
let list: any[] = [1,2,3,'4'];
// symbol
let s:symbol = Symbol('s');
// boolean
let isTrue: boolean = true;
// undefined
let u: undefined = undefined;
// null
let n: null = null;
// 定义多种类型
let s:string|undefined;
```
扩展类型
-
元组
Tuple元组作为有组织的数组,需要以正确的顺序预定义数据类型。
const tuple: [number, string, string] = [24, "Indrek" , "Lasn"]; const arr3:[string, number] = ['12',1]; -
枚举
enumenum类型是对JavaScript标准数据类型的一个补充。 像C#等其它语言一样,使用枚举类型可以为一组数值赋予友好的名字。enum Flag { success = 0, error = 1 } let c: Flag = Flag.success; // 0 let d: string = Flag[0]; // success -
Any表示任意类型,慎重使用,用多了就失去使用Ts的意义
用于类型不明确的情况
-
Void- 在Typescript中,你必须在函数中定义返回类型
- 我们可以将其返回值定义为void
- 用void定义的函数不能写return
function run():void{ console.log('run') } -
neverNever是永远达不到的值// 返回never的函数必须存在无法达到的终点 function error(message: string): never { throw new Error(message); } // 推断的返回值类型为never function fail():never { return error("Something failed"); } // 返回never的函数必须存在无法达到的终点 function infiniteLoop(): never { while (true) { } }
函数
- 函数声明
function run():string { console.log('ru') return 'su' } - 函数表达式
const run = function():void{ console.log('run') } - 可选参数
- ES5中的实参和形参个数可以不一样,TS中必须一致。如果不一致必须设置可选参数
- 可选参数必须位于非可选参数后
function getInfo(name:string, age?: number):string{ if(age) { return `${name}---${age}` } else { return `${name}---年龄无` } }
-
默认参数
ES6中提供了默认参数的方法,TS中也可以使用
function getInfo(name:string, age: number=20):string{ return `${name}---${age}` } -
剩余参数
ES6中的参数解构
function sum(...args:number[]):number { let num:number = 0; for (let i = 0;i < args.length; i++) { num += args[i] } return num } -
函数重载
-
在JAVA中函数的重载是函数名称相同,参数不同。通过传的参数来执行不同的方法
-
TS为了兼容JS,重载写法不同
// 定义方法参数及返回值类型 function getInfos(name:string):string; function getInfos(age: number):number; // 判断执行哪个函数分别执行 function getInfos(str:any):any { if (typeof str === 'string') { return str // name值 } else { return str // age值 } }
-
箭头函数
特性 同ES6中的箭头函数
类
-
ES5中的类
function Person(name, age) { this.name = name this.age = age } Person.prototype.say = function() { console.log(this.name + 'hello') } // 添加静态方法 Person.print = function() { console.log(print) } -
ES5的继承
funtion Man(name, age, sex) { this.sex = sex Person.call(this, name, age) } Man.prototype = Object.create(Person.prototype, { constructor: { value: Man } }) -
TS中的类
class Person { name:string; // 属性,省略了public关键字 age: number; constructor (name:string, age:number) { // 构造函数,在实例化的时候执行 this.name = name; this.age = age; } say():void { console.log(this.name + 'hello') } getName():string{ return this.name } setName(name:string):void { this.name = name } } -
TS中的继承
class Man extends Person{ sex:boolean; constructor (name:string,age:number,sex:boolean) { super(name, age); // 初始化父类的构造函数 this.sex = sex; } say():void { console.log(this.name + 'hello,我是子类的') } } -
类中的修饰符
在typescipt中,定义属性时,提供了三种访问修饰符
public公有的,都可以访问protected在类里面,子类里面可以访问,类外部无法访问private在类里面可以访问,子类和外部都不能访问
属性如果不加修饰符,默认为public
-
类中的静态方法与静态属性
用static修饰
-
多态
父类定义一个方法没有实现,每一个子类都有不同的实现
-
抽象类
- 抽象类是提供其他类继承的基类,不能被实例化
- 用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
- 抽象方法必须在抽象类中
abstract class Animal { name:string; constructor(name:string) { this.name = name } abstract eat():any; } class Dog extends Animal{ constructor(name:string) { super(name) } eat():void { console.log(this.name + 'eat') } }
接口
在面向对象的编程中,接口是一种规范定义,定义了行为和动作的规范。在程序设计里,接口起到限制和规范的作用
- 属性类接口
interface FullName { firstName:string; lastName:string; age?: number; // 接口的可选属性 } function getName(name:FullName): void { console.log(name.firstName + name.lastName) } getName({firstName: '张三', lastName: 'hehe'}); - 函数类接口
interface Encrypt { (key:string, value:string):string } const md5:Encrypt = function (key:string, value:string):string { console.log(key + value); return key + value }; - 类类型接口 有点类似抽象类
interface Animal { name: string eat(str:string): void } class Dog implements Animal{ name:string; constructor(name:string) { this.name = name } eat(str: string): void { console.log(this.name + '吃'); } } - 接口的继承
interface Animal { eat():void } interface People extends Animal{ work():void } class Web implements People{ constructor() { } eat(): void { } work(): void { } }
泛型
要创建一个可重用的组件,其中的数据类型就必须要兼容很多的类型,那么如何兼容呢,TypeScript提供了一个很好的方法:泛型
要兼容多种数据格式,可能会有人想到any
function getData(value:any):any{
return value
}
存在有可能传入的值和返回的值不是同一种值,例如,传入数字,但是不确定返回的是什么值
// 定义泛型
function getData<T>(args:T):T {
return args
}
const data = getData<number>(123)
const data = getData(123) // 类型推断
泛型类
class FilteredList<T> {
// 声明过滤器是以 T 为参数类型,返回 boolean 的函数表达式
filter: (v: T) => boolean;
// 声明数据是 T 数组类型
data: T[];
constructor(filter: (v: T) => boolean) {
this.filter = filter;
}
add(value: T) {
if (this.filter(value)) {
this.data.push(value);
}
}
get all(): T[] {
return this.data;
}
}
// 处理 string 类型的 FilteredList
const validStrings = new FilteredList<string>(s => !s);
// 处理 number 类型的 FilteredList
const positiveNumber = new FilteredList<number>(n => n > 0);
泛型接口
// 方式1
interface Config {
<T>(value:T):T;
}
const setData:Config = function<T>(value:T):T {
return value
};
setData<number>(123)
// 方式2
interface Config2<T> {
(value:T):T
}
function getData<T>(value:T):T {
return value
}
const myGetData:Config2<string> = getData;
把类当做参数的泛型类
class User {
username: string;
password: string;
constructor(username:string, password:string) {
this.username = username;
this.password = password
}
}
class MysqlDb<T> {
add(info:T): boolean {
console.log(info);
return true
}
}
const u = new User('hedekun', '123456');
const db = new MysqlDb<User>();
db.add(u);
装饰器
装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上,可以修改类的行为。 装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。
- 类装饰器
function Path(path: string) {
return function (target: Function) {
!target.prototype.$Meta && (target.prototype.$Meta = {})
target.prototype.$Meta.baseUrl = path;
};
}
@Path('/hello')
class HelloService {
constructor() {}
}
console.log(HelloService.prototype.$Meta);// 输出:{ baseUrl: '/hello' }
let hello = new HelloService();
console.log(hello.$Meta) // 输出:{ baseUrl: '/hello' }
- 属性装饰器 接受两个参数
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 成员的名字。
function logProperty(params:string) {
return function (target: any,key:string) {
let _val = this[key];//属性值
const getter = function () {
console.log(`Get:${key} => ${_val}`);
return _val;
};
const setter = function () {
console.log(`Set:${key} => ${params}`);
_val = params;
};
//删除属性,在严格模式下,如果对象是不可配置的,将会抛出一个错误。否则返回false
if (delete this[key]) {
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable:true
})
}
}
}
class Test {
@logProperty('taobao')
public url:any = 'http://www.baidu.com';
constructor() {
// console.log(this.url)
}
getData():void {
console.log(this.url)
}
}
const t:any = new Test();
t.getData();
- 方法装饰器 它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。 方法装饰会在运行时传入下列3个参数:
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 成员的名字。
- 成员的属性描述符{value: any, writable: boolean, enumerable: boolean, configurable: boolean}。
function get(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const oMethods = descriptor.value;
descriptor.value = function (...args:any[]) {
args = args.map(item => String(item));
oMethods.call(this,...args)
}
}
class Hello{
name: string;
age: number;
constructor() {
console.log('hello');
this.name = 'yugo';
}
@get
hello(...args:any[]){
console.log(args);
console.log('这是原来的方法')
}
}
const h:any = new Hello();
h.hello(123, 'xxx');
- 方法参数装饰器 参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 参数的名字。
- 参数在函数参数列表中的索引。
function PathParam(paramName: string) {
return function (target, methodName: string, paramIndex: number) {
!target.$Meta && (target.$Meta = {});
target.$Meta[paramIndex] = paramName;
}
}
class HelloService {
constructor() { }
getUser( @PathParam("userId") userId: string) { }
}
console.log((<any>HelloService).prototype.$Meta); // {'0':'userId'}
装饰器执行顺序
function ClassDecorator() {
return function (target) {
console.log("I am class decorator");
}
}
function MethodDecorator() {
return function (target, methodName: string, descriptor: PropertyDescriptor) {
console.log("I am method decorator");
}
}
function Param1Decorator() {
return function (target, methodName: string, paramIndex: number) {
console.log("I am parameter1 decorator");
}
}
function Param2Decorator() {
return function (target, methodName: string, paramIndex: number) {
console.log("I am parameter2 decorator");
}
}
function PropertyDecorator() {
return function (target, propertyName: string) {
console.log("I am property decorator");
}
}
@ClassDecorator()
class Hello {
@PropertyDecorator()
greeting: string;
@MethodDecorator()
greet( @Param1Decorator() p1: string, @Param2Decorator() p2: string) { }
}
输出结果
I am property decorator
I am parameter2 decorator
I am parameter1 decorator
I am method decorator
I am class decorator
-
有多个参数装饰器时:从最后一个参数依次向前执行
-
方法和方法参数中参数装饰器先执行。
-
类装饰器总是最后执行。
-
方法和属性装饰器,谁在前面谁先执行。因为参数属于方法一部分,所以参数会一直紧紧挨着方法执行。