typescript 快速上手

假如翻到了此文章,如果你写过类似java,c#等强类型面向对象语言,就可以阅读此文,迅速入手TS,否则就移步到此:https://ts.xcatliu.com/introduction/what-is-typescript.html

ts:
优点:1,增加了代码的可读性和可维护性(编译阶段就发现大部分错误,优越于运行时发现错误)
2,TypeScript 最大的优势便是增强了编辑器和 IDE 的功能,包括代码补全、接口
提示、跳转到定义、重构等。

1、 原始类型

boolen  number null undefine    stirng   object

2、任意值:

let anything:any="sss"
let anyThing: any = 'Tom';
anyThing.setName('Jerry');
anyThing.setName('Jerry').sayHello();
anyThing.myName.setFirstName('Cat');

3、未声明类型—>识别成any
let somethine; //此处没有声明类型
4、类型推论
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查:

let myFavoriteNumber;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;

5、联合类型

let myFavoriteNumber: string | number|bollen|null

此时:myFavoriteNumber='harry' myFavoriteNumber='number' myFavoriteNumber=true 等都是对的
参数:

function getLength(something: string | number): number {
    return something.length;       //注意:此时如果不是联合类型的共有属性就会报错
}

6、接口:
命名规范 I开头,如Iperson{} //
1、在没有可选属性,任意属性前提下实现接口时属性数量必须跟接口一致

2、任意属性/可选属性:

interface:Iperson{
            name: string;
            age?: number;       //可选属性:这样写,实现接口时,这属性有无均可
       [propName: string]: any; //任意属性,这个字段随便写
         }

3、只读属性

interface Person {
          readonly id: number;   //只读
                 name: string;
                 age?: number;
   [propName: string]: any;
}


interface Person {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}

error:此处实现接口的时候没有对只读属性id进行赋值

let tom: Person = {
   name: 'Tom',
 gender: 'male'
};

error:因为是只读不能修改,所以error:tom.id = 89757;

数组:
1、常规数组:let stringArr:string[]=["A","B","C","D"]

   let numberArr:string[]=[1,2,3,4]

2、数组泛型

let  Tarr:Array<>

例子:

let fibonacci: Array<number> = [1, 1, 2, 3, 5];

let fibonacci: Array<any> = [1, 1, 2, 3, 5]; //任意类型
3、用接口表示数组

interface NumberArray{
    [index:number]:number
}

4,any 在数组中的应用
let list: any[] = ['Xcat Liu', 25, { website: 'http://xcatliu.com' }];//数组中各种类型数据都可以有

5,类数组-不是数组类型

function sum() {
    let args: number[] = arguments;
}

函数:
function sum(x: number, y: number): number { //指定参数类型,指定返回值类型

    return x + y;
}

sum(1, 2); //传参多,少,类型不对都会报错

1、函数定义

写法1:

let mySum = function (x: number, y: number): number {
    return x + y;
};

这是可以通过编译的,不过事实上,上面的代码只对等号右侧的匿名函数进行了类型定义,而等号左边的 mySum,是通过赋值操作进行类型推论而推断出来的。

推荐写法:

let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y;
};

不要混淆了 TypeScript 中的 => 和 ES6 中的 =>。
在 TypeScript 的类型定义中,=> 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。

采用接口定义函数

interface IDemoFun {
  (source: string, sub: string): boolean;
}
let demoFun: IDemoFun;
demoFun = function(source: string, sub: string) { 
  return source.search(sub) != -1;
};

可选参数:可选参数必须接在必需参数后面。换句话说,可选参数后面不允许再出现必须参数了

function buildName(firstName: string, lastName?: string) {     //?可选可以不传
    if (lastName) {
        return firstName + ' ' + lastName;
    } else {
        return firstName;
    }
}

参数默认值:我们允许给函数的参数添加默认值,TypeScript 会将添加了默认值的参数识别为可选参数:

function buildName(firstName: string, lastName: string = 'Cat') {
    return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');

剩余参数:

function push(array, ...items) {
    items.forEach(function(item) {
        array.push(item);
    });
}
let a = [];
push(a, 1, 2, 3);

items 是一个数组。所以我们可以用数组的类型来定义它:

function push(array: any[], ...items: any[]) {
    items.forEach(function(item) {
        array.push(item);
    });
}

函数重载:允许一个函数接受不同数量或类型的参数时,作出不同的处理

function reverse(x: number): number;  //重载1
function reverse(x: string): string;  //重载2
function reverse(x: number | string): number | string {  //实现函数
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

类型断言(Type Assertion):可以用来手动指定一个值的类型。

语法:<类型>值

function getLength(something: string | number): number {
    if (something.length) { //error:此处报错因为number类型是没有length属性的
        return something.length;
    } else {
        return something.toString().length;
    }
}

使用断言:

function getLength(something: string | number): number {
    if ((<string>something).length) {  //<类型> 值
        return (<string>something).length;
    } else {
        return something.toString().length;
    }	
}

文件声明:

1、声明语句
以jquery为例
通常页面使用jquery $("#id") 但是ts并不知道这是什么意思
所以我们要声明引入的第三方库

declare var jQuery: (selector: string) => any;

2、声明引入文件
@types 的使用方式很简单,直接用 npm 安装对应的声明模块即可,以 jQuery 举例:

npm install @types/jquery --save-dev

内置对象:

用 TypeScript 写 Node.js
Node.js 不是内置对象的一部分,如果想用 TypeScript 写 Node.js,则需要引入第三方声明文件:

npm install @types/node --save-dev

类型别名
使用 type 创建类型别名
例如:

type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;

//使用别名

function getName(n: NameOrResolver): Name {
    if (typeof n === 'string') {
        return n;
    } else {
        return n();
    }
}

字符串字面量类型:用来约束取值只能是某几个字符串中的一个。

type EventNames = 'click' | 'scroll' | 'mousemove';  //使用type定义了字面量类型
function handleEvent(ele: Element, event: EventNames) { //使用了字面量类型 
    // do something
}
handleEvent(document.getElementById('hello'), 'scroll');  // 没问题  //在约束范围
handleEvent(document.getElementById('world'), 'dbclick'); // 报错,event 不能为 'dbclick' 不在约束范围

元组:数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。

let  arr:[string,number,boolen]=["fuck",123,true]

当赋值或访问一个已知索引的元素时,会得到正确的类型:

let xcatliu: [string, number];
xcatliu[0] = 'Xcat Liu';
xcatliu[1] = 25;

xcatliu[0].slice(1);
xcatliu[1].toFixed(2);

let xcatliu: [string, number];
xcatliu[0] = 'Xcat Liu';

越界元素:当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型:

let xcatliu: [string, number];
xcatliu = ['Xcat Liu', 25];
xcatliu.push('http://xcatliu.com/');
xcatliu.push(true);

枚举(Enum):类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等,一般枚举有两种:常数项和计算所得项

1、常数项-普通枚举

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射:

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true
console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
console.log(Days[6] === "Sat"); // true

手动赋值:未手动赋值的枚举项会接着上一个枚举项递增。

enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};
console.log(Days["Sun"] === 7); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true

手动自动区别:
如果未手动赋值的枚举项与手动赋值的重复了,TypeScript 是不会察觉到这一点的:
当然也可以是小数或者负数,但是后续增长得增步长依旧是1

enum Days {Sun = 3, Mon = 1, Tue, Wed, Thu, Fri, Sat};
console.log(Days["Sun"] === 3); // true
console.log(Days["Wed"] === 3); // true
console.log(Days[3] === "Sun"); // false
console.log(Days[3] === "Wed"); // true

2、计算所得项
enum Color {Red, Green, Blue = "blue".length}; //标红即是计算所得项
但是如果紧接在计算所得项后面的是未手动赋值的项,那么它就会因为无法获得初始值而报错:

枚举成员被当做常数条件
不具有初始化函数并且之前的枚举成员是常数。在这种情况下,当前枚举成员的值为上一个枚举成员的值加 1。但第一个枚举元素是个例外。如果它没有初始化方法,那么它的初始值为 0。
枚举成员使用常数枚举表达式初始化。常数枚举表达式是 TypeScript 表达式的子集,它可以在编译阶段求值。当一个表达式满足下面条件之一时,它就是一个常数枚举表达式:
数字字面量
引用之前定义的常数枚举成员(可以是在不同的枚举类型中定义的)如果这个成员是在同一个枚举类型中定义的,可以使用非限定名来引用
带括号的常数枚举表达式
+, -, ~ 一元运算符应用于常数枚举表达式
+, -, *, /, %, <<, >>, >>>, &, |, ^ 二元运算符,常数枚举表达式做为其一个操作对象。若常数枚举表达式求值后为 NaN 或 Infinity,则会在编译阶段报错
所有其它情况的枚举成员被当作是需要计算得出的值。

常数枚举和普通枚举区别:常数枚举会在编译阶段被删除,并且不能包含计算成员。

3、常数枚举

const enum Directions {
    Up,
    Down,
    Left,
    Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right]

4、外部枚举:declare enum 定义的枚举类型:

declare enum Directions {
    Up,
    Down,
    Left,
    Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];

declare: 定义的类型只会用于编译时的检查,编译结果中会被删除

类:
类(Class):定义了一件事物的抽象特点,包含它的属性和方法
对象(Object):类的实例,通过 new 生成
面向对象(OOP)的三大特性:封装、继承、多态
封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据
继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比如 Cat 和 Dog 都继承自 Animal,但是分别实现了自己的 eat 方法。此时针对某一个实例,我们无需了解它是 Cat 还是 Dog,就可以直接调用 eat 方法,程序会自动判断出来应该如何执行 eat
存取器(getter & setter):用以改变属性的读取和赋值行为
修饰符(Modifiers):修饰符是一些关键字,用于限定成员或类型的性质。比如 public 表示公有属性或方法
抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现
接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现(implements)。一个类只能继承自另一个类,但是可以实现多个接口

es6/7中的类的体现

类:

class Animal {
  name:string;
  constructor(name) {
    this.name = name;
  }
  sayHi() {
    return `my name is ${this.name} `;
  }
}

let a = new Animal("harry");
console.log(a.sayHi());

继承:

class Cat extends Animal {
  constructor(name) {
    super(name);
  }
  sayHi() {
    return "Cat" + super.sayHi();
  }
}
let c = new Cat("Cat");
console.log(c.sayHi());

存取器:

class An{
  name:string;
  constructor(name){
    this.name=name
  }
  get(){
    return this.name
  }
  set(value){
    console.log("set",value)
  }
}

let A=new An("what the fucker")
 console.log("get",A.get()) //获取
 console.log(A.set("lalla"))//写入

静态属性:static直接通过类来调用

class Anim {
  static isAnimal(obj) {
    return obj instanceof Anim;
  }
}
let ani = new Anim();
console.log("static", Anim.isAnimal(ani)); //直接通过类调用

TS中类的用法

修饰符:
public: 公共权限,默认属性,任何地方都能访问到
private:私有的,只能在类内部使用

class ClassDemo {
  private name: string;
  public constructor(name) {
    this.name = name;
  }
}

let cd = new ClassDemo("harry");

console.log(cd.name); //error 无法访问,只能在类内部使用
protect:私有,在类和子类中使用

class ClassDemo {
  protected name: string;
  constructor(name) {
    this.name = name;
  }
}
class pro extends ClassDemo{
    constructor(name){
      super(name)
    }
}

let p=new pro("sssssss")
p.name="ddd" //error 只能在子类内使用

抽象类:用于定义抽象类和其中的抽象方法
继承抽象类必须实现其中的方法

abstract class absDemo {
  protected name: string;
  constructor(name) {
    this.name = name;
  }
  protected abstract sayHi();
}

class demo extends absDemo { //继承抽象类
  constructor(name) {
    super(name);
  }
  sayHi() { //必须实现抽象类中的方法
    console.log("xxxx", this.name);
  }
}

let d=new demo("harry")
d.sayHi();

类和接口的继承关系

1、类实现接口

   interface tool {
      open();
    }
    
class Door {
  type: string;
  DoorType(type) {
    this.type = type;
  }
}

class car extends Door implements tool {  //继承类,实现接口
  open() {
    console.log("open car doors");
  }
  DoorType() {
    console.log("type", this.type);
  }
}

let C = new car();
C.open();
C.DoorType();
C.type = "CAR";

2、类实现多个接口

interface tool {
  open();
}

interface Door {
  DoorType(type);
}

class car implements tool, Door {  //实现多个接口
  open() {
    console.log("open car doors");
  }
  DoorType(type) {
    console.log("type", type);
  }
}
let C = new car();
C.open();
C.DoorType("car")

3、接口继承接口

interface tool {
  open();
}

interface Door extends  tool {  //接口继承接口
  DoorType(type);
}

class car implements tool, Door {
  open() {
    console.log("open car doors");
  }
  DoorType(type) {
    console.log("type", type);
  }
}

let C = new car();
C.open();
C.DoorType("car")

4、接口继承类

class Point {
    x: number;
    y: number;
}
interface Point3d extends Point {
    z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};

5、混合继承

interface SearchFunc {
    (source: string, subString: string): boolean; //接口的方式来定义一个函数需要符合的形状:
}

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
    return source.search(subString) !== -1;
}

//接口中有时根据子类需求还有公共字段属性
interface Counter {
    (start: number): string;
    interval: number; //字段成员
    reset(): void;
}

function getCounter(): Counter {
    let counter = <Counter>function (start: number) { };
    counter.interval = 123;
    counter.reset = function () { };
    return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;  //使用字段

泛型:在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

function createArray<T>(length: number, value: T): Array<T> { //泛型典型应用
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray<string>(3, 'x'); // ['x', 'x', 'x']

元组:多参数

function swap<T, U>(tuple: [T, U]): [U, T] {
    return [tuple[1], tuple[0]];
}
swap([7, 'seven']); // ['seven', 7]

泛型约束

interface Lengthwise {
    length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {  //继承接口,自动约束必须有length属性
    console.log(arg.length);
    return arg;
}

loggingIdentity(7); //error:因为参数不包含length属性就会报错

参数相互约束

function copyFields<T extends U, U>(target: T, source: U): T {
    for (let id in source) {
        target[id] = (<T>source)[id];
    }
    return target;
}
let x = { a: 1, b: 2, c: 3, d: 4 };
copyFields(x, { b: 10, d: 20 });

上例中,我们使用了两个类型参数,其中要求 T 继承 U,这样就保证了 U 上不会出现 T 中不存在的字段。

泛型接口:

interface CreateArrayFunc<T> {
    (length: number, value: T): Array<T>;
}

let createArray: CreateArrayFunc<any>;
createArray = function<T>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray(3, 'x'); // ['x', 'x', 'x']

泛型类:

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

//指定默认类型

function createArray<T = string>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

声明合并:

函数合并

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
interface Alarm {
    price: number;
}
interface Alarm {
    price: string;  // 类型不一致,会报错
    weight: number;
}

    return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
    return x.split('').reverse().join('');
}

接口合并:

}interface Alarm {
    price: number;
}
interface Alarm {
    weight: number;
}

相当于:

interface Alarm {
    price: number;
    weight: number;
}

注意,合并的属性的类型必须是唯一的:

interface Alarm {
    price: number;
}
interface Alarm {
    price: number;  // 虽然重复了,但是类型都是 `number`,所以不会报错
    weight: number;
}

============
interface Alarm {
    price: number;
    alert(s: string): string;
}
interface Alarm {
    weight: number;
    alert(s: string, n: number): string;
}
相当于:
interface Alarm {
    price: number;
    weight: number;
    alert(s: string): string;
    alert(s: string, n: number): string;
}

代码检查:

tslint  eslint
发布了29 篇原创文章 · 获赞 16 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_38560742/article/details/87776787
今日推荐