TS用法整理

介绍

1.是js的超级,遵循es6 es5的规范,扩展了js语法
2.像java面向对象语言(规范、工程化、模块话),适合开发大型企业项目

介绍用法:数据类型、函数、接口、类、泛型、装饰器。

数据类型(11种)

1.布尔类型 boolean
2.数字类型 number
3.字符串类型 string
4.数组类型 array
数组定义的三种方式
(1) 在元素类型后面接上 []:let list: number[] = [1, 2, 3];
(2)数组泛型,Array<元素类型>:let list: Array = [1, 2, 3];
(3)定义元组数组:let list:any[]=[1,‘2’,3]
5.元组类型 tuple
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同

let x: [string, number];
x = ['hello', 10]; // OK
x = [10, 'hello']; //Error

6.枚举类型 enum
定义一些带名字的常量,默认情况下,从0开始为元素编号。 你也可以手动的指定成员的数值,也可以全部都采用手动赋值,可读性强。
枚举类型提供的一个便利是你可以由枚举的值得到它的名字。 例如,我们知道数值为2,但是不确定它映射到Color里的哪个名字,我们可以查找相应的名字(适用于值为数字)

enum Color {Red, Green, Blue}
let c: Color = Color.Green;
let colorName: string = Color[2];
console.log(c,Color[0],Color1[1],colorName);  // 1 'Red' 'Green' 'Blue'
enum Color1 {Red = 1, Green = 2, Blue = 4}
let c1: Color1 = Color1.Green;
console.log(c1,Color[2]);  // 2 'Green'
enum Color3 {Red = 'nihao', Green='aaaa', Blue='bbb'}
let colorName3: string = Color3[2];
console.log(colorName3);  // Blue
console.log(Color3['aaaa']);  // 报错

7.任意类型 any
在编程阶段还不清楚类型的变量指定一个类型
8.void
void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void:

function warnUser(): void {
    console.log("This is my warning message");
}

9.undefined和null
TypeScript里,undefined和null两者各自有自己的类型分别叫做undefined和null。 和 void相似,它们的本身的类型用处不是很大:
默认情况下null和undefined是所有类型的子类型。 就是说你可以把 null和undefined赋值给number类型的变量。
10.never

// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
    throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
    return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
    while (true) {
    }
}

11.object
object表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。

12.类型断言
你会比TypeScript更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型
类型断言有两种形式。 其一是“尖括号”语法,另一个为as语法:

let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
let strLength: number = (someValue as string).length;//推荐

注意:断言并不是类型转换,断言联合类型中不存在的类型会报错

let strLength: number
function getLen(someValue: number|string){
    if(someValue as string){
        strLength=(someValue as string).length
    }
    if(someValue as number){
        strLength=(someValue as number).toString().length
    }
    if(someValue as boolean){//报错
        
    }
}
getLen('this is a string');

函数

和js不一样的是在定义的时候需要加上数据类型

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

可选参数和默认参数
可选:没传参的时候,它的值就是undefined。 在TypeScript里我们可以在参数名旁使用 ?实现可选参数的功能,可选参数必须跟在必须参数后面。

function buildName(firstName: string, lastName?: string) {
    // ...
}

剩余参数
必要参数,默认参数和可选参数有个共同点:它们表示某一个参数。 有时,你想同时操作多个参数,或者你并不知道会有多少参数传递进来。 在JavaScript里,你可以使用 arguments来访问所有传入的参数。

function sum(...result:number[]):number {
    let sumV=0;
    result.forEach((item) => {
        sumV+=item
    })
    return sumV
}
console.log(sum(1,2,3,4))

接口

用来建立某种代码定义契约,使得其他开发者在调用某个方法或创建新的类型时必须遵守接口定义的代码约定
(1) interfere:用来声明接口
(2)implements:一个类必须实现接口的方法

//初探
function printLabel(labelledObj: { label: string }) {
  console.log(labelledObj.label);
}
let myObj = { size: 10 };
printLabel(myObj);
//ts并不会那么宽松,ts必须传带label属性的对象
//ts的正确写法
function printLabel(labelledObj: { label: string }) {
  console.log(labelledObj.label);
}
let myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);
//ts接口重写
interface LabelledValue {
  label: string;
}
function printLabel(labelledObj: LabelledValue) {
  console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);

接口可选属性
接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。 可选属性在应用“option bags”模式时很常用,即给函数传入的参数对象中只有部分属性赋值了。

interface SquareConfig {
  color?: string;
  width?: number;
}
function createSquare(config: SquareConfig): {color: string; area: number} {
  let newSquare = {color: "white", area: 100};
  if (config.color) {
    newSquare.color = config.color;
  }
  if (config.width) {
    newSquare.area = config.width * config.width;
  }
  return newSquare;
}
let mySquare = createSquare({color: "black"});

只读属性
一些对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用 readonly来指定只读属性:

interface Point {
    readonly x: number;
    readonly y: number;
}
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!

TypeScript具有ReadonlyArray类型,它与Array相似,只是把所有可变方法去掉了,因此可以确保数组创建后再也不能被修改:

let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!

readonly vs const
最简单判断该用readonly还是const的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const,若做为属性则使用readonly。20,color_FFFFFF,t_70,g_se,x_16)

额外的属性检查
对象字面量会被特殊对待而且会经过 额外属性检查,当将它们赋值给变量或作为参数传递的时候。 如果一个对象字面量存在任何“目标类型”不包含的属性时,你会得到一个错误

//看个例子
interface LabelledValue {
  label: string;
}
function printLabel(labelledObj: LabelledValue) {
  console.log(labelledObj.label);
}
printLabel({size: 10, label: "Size 10 Object"});//报错

绕开这些检查的三种方法
1)类型断言

printLabel({size: 10, label: "Size 10 Object"} as SquareConfig);//SquareConfig为{label:string}或LabelledValue
//用法
printLabel({size: 10, label: "Size 10 Object"} as LabelledValue);

2)将这个对象赋值给一个另一个变量

//就是上面第一个接口例子的用法

3)添加字符串的索引

interface LabelledValue {
  label: string;
  [propName:string]:any//propName可自定义名字
}
function printLabel(labelledObj: LabelledValue) {
  console.log(labelledObj.label);
}
printLabel({size: 10, label: "Size 10 Object",age:10});

思考一下如何对值为字符串或者数字的数组约束?

interface arr{
	[propName:number]:string|number
}
var myArr:arr=[1,'hello',2,3];
console.log(myArr)

类类型接口(接口的实现)implements
接口中有多少内容,定义类的时候就要把这些内容都实现

interface Fullname{
    username:string
}
class GetUser implements Fullname {
    username:string;//没有username就会报错
    age:number
    constructor(username:string,age:number){
        this.username=username;
        this.age=age
    }
}
var user1=new GetUser('张三',23);
console.log(user1)

接口可以继承接口

interface Animail{
    eat():void
}
interface People extends Animail{
    work():void
}
//多继承
interface People extends 接口1,接口2...

定义:

class Greeter {
    greeting: string;
    constructor(message: string) {//构造函数
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}
let greeter = new Greeter("world");

继承
关键字extends、super,允许使用继承来扩展现有的类。
派生类/子类包含了一个构造函数,它 必须调用 super(),它会执行基类的构造函数。 而且,在构造函数里访问 this的属性之前,我们 一定要调用 super()。 这个是TypeScript强制执行的一条重要规则。子类没有写出自己的构造函数(默认构造函数)则可不用调用super

class Animal {
    name: string;
    constructor(theName: string) { this.name = theName; }
    move(distanceInMeters: number = 0) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}
class Snake extends Animal {
    constructor(name: string) { 
    	super(name); //关键字,调用父类构造函数和方法
    }
    move(distanceInMeters = 5) {
        console.log("Slithering...");
        super.move(distanceInMeters);
    }
}

公共,私有与受保护的修饰符*
1.默认为 public:在当前类,子类,类外面都可访问;
2.private:只有在当前类可以访问;
3.protected:在当前类和子类中可以访问。

静态属性
存在于类本身上面而不是类的实例上,不是使用 this. 来访问,而是使用 类名. 访问

class Grid {
    static origin = {x: 0, y: 0};
    calculateDistanceFromOrigin(point: {x: number; y: number;}) {
        let xDist = (point.x - Grid.origin.x);
        let yDist = (point.y - Grid.origin.y);
        return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
    }
    constructor (public scale: number) { }
}
let grid1 = new Grid(1.0);  // 1x scale
let grid2 = new Grid(5.0);  // 5x scale
console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));

多态
父类定义一个方法不去实现,让继承他的子类去具体实现,每一个子类有不同的表现。(子类可以不去实现父类的方法)

class Animal {
    name: string;
    constructor(theName: string) { this.name = theName; }
    eat(){
        
    }
}
class Dog extends Animal {
    constructor(name: string) {
        super(name);
    }
    eat(){
        console.log(this.name+'吃粮食')
    }
}
class Snake extends Animal {
    constructor(name: string) {
        super(name);
    }
}

抽象类
抽象类做为子类的基类使用, 它们一般不会直接被实例化,不同于接口,抽象类可以包含成员的实现细节。(子类必须去实现父类的抽象方法)

abstract class Animal {
    name: string;
    constructor(theName: string) { this.name = theName; }
    abstract eat():void
}
class Dog extends Animal {
    constructor(name: string) {
        super(name);
    }
    eat(){
        console.log(this.name+'吃粮食')
    }
}
class Snake extends Animal {//报错

}

泛型

对类 接口 方法的复用性,以及对不特定数据类型的支持,使用泛型可以来创建可重用性的组件(参数支持多种类型),可以兼容各种类型(接口的类型是在定义的时候就固定好了),而泛型是在输入的时候去指定。(一般用T表示,具体什么类型是调用这个方法的时候决定的)

function getDate<T>(value:T):T {
    return value
}
console.log(getDate<string>('hello'));
console.log(getDate<number>(123));
//当然可以用any定义可重用性的组件,但是any放弃了类型检测,这样传入的参数类型可以不一样,任何类型都有可能是被返回的

泛型类

class GetMax<T> {
    arr:T[];
    constructor(arr:T[]){
        this.arr=arr
    }
    add(item:T):void{
        this.arr.push(item)
    };
    max():T{
        let maxV=this.arr[0];
        this.arr.forEach(val => {
            if(maxV<val){
                maxV=val
            }
        })
        return maxV
    }
}
let maxObj=new GetMax<number>([1,2,3]);
maxObj.add(4);
console.log(maxObj.max());//4
let maxObj1=new GetMax<string>(['x','y','h']);
console.log(maxObj1.max());//y

泛型接口

interface ConfigFn<T> {
    (value1:T,value2:T):T//定义的函数
}
let setDate:ConfigFn<number>=function <T>(val1:T,val2:T):T{
    return val1;    
}
console.log(setDate(2,5))//2

在使用的时候再指定类型的写法:

interface ConfigFn {
    <T>(value1:T,value2:T):T//定义的函数
}
let setDate:ConfigFn=function <T>(val1:T,val2:T):T{
    return val1;
    
}
console.log(setDate<number>(2,5))//2

装饰器

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上,可以修改类的行为。通俗讲就是一个函数方法,扩展功能(不改变原来的类、方法、属性等)。
为什么使用:有时候我们会对传入的参数类型进行判断、对返回的值排序过滤,对函数添加节流、防抖或者其他功能性代码。(在js编译阶段去执行)
还属于实验性语法,必须在命令行或者配置文件tsconfig.json启用"experimentalDecorators": true,

function helloWord(target:any) {//target为当前类
    target.prototype.url="http://www.baidu.com"
    console.log('hello',target.prototype.url)
}
@helloWord
class HelloWordClass {
}
let obj=new HelloWordClass()

普通装饰器
无法传参,使用:@函数名

装饰器工厂
采用闭包传参
方法装饰器

function helloWord(param:string) {//target为当前类
    return function(target:any){
        target.prototype.url="http://www.baidu.com"
        console.log('hello',target.prototype.url,param)
    }
}
@helloWord('装饰参数')
class HelloWordClass {
}
let obj=new HelloWordClass();
console.log(obj.constructor.prototype.url);

类装饰器

function helloWord(target:any) {//target为当前类
    return class Test extends target{
        str:string='修改后的值';
        work(){
            console.log(target,'扩展功能',this.str)
        }
    }
}
@helloWord
class HelloWordClass {
    str:string;
    constructor(str:string){
        this.str=str
    }
    work(){
        console.log(this.str)
    }
}
let obj=new HelloWordClass('this is string');

属性装饰器
1)对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2)成员的名字。

function helloWord(param:string) {//target为当前类
    return function (target:any,attr:any) {
        target[attr]=param
        console.log(param,target[attr],attr)
    }
}
class HelloWordClass {
    @helloWord('http://')
    url:string|undefined;
    @helloWord('lili')
    name:string|undefined;
    str:string;
    constructor(str:string){
        this.str=str
    }
    getUrl(){
        console.log(this.url,this.name)
    }
}
let obj=new HelloWordClass('www.baidu.com');
obj.getUrl()
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值