专业编程基础技术教程

网站首页 > 基础教程 正文

一波Ts 基础大全;领先同事的机会来了

ccvgpt 2024-11-25 10:12:19 基础教程 1 ℃


什么是 TypeScript:

TypeScript 是 JavaScript 的一个超集,主要提供了类型系统和对 ES6 的支持,它由 Microsoft 开发,代码开源于 GitHub 上。

一波Ts 基础大全;领先同事的机会来了

官网:https://www.tslang.cn/

特点:

  • 可以在编译阶段就发现大部分错误,这总比在运行时候出错好
  • 不显式的定义类型,也能够自动做出类型推论
  • 即使 TypeScript 编译报错,也可以生成 JavaScript 文件
  • Google 开发的 Angular 就是使用 TypeScript 编写的
  • TypeScript 拥抱了 ES7 规范,也支持部分 ES8 草案的规范

缺点:

有一定的学习成本,需要理解接口(Interfaces)、泛型(Generics)、类(Classes)、枚举类型(Enums)等前端工程师可能不是很熟悉的东西

短期可能会增加一些开发成本,多写一些类型的定义,长期维护的项目,TypeScript 能够减少其维护成本

安装:

          npm install -g typescript

以上命令将会安装typescript编译器和可执行程序(tsc),并且添加到环境变量的全局路径中 tsc -v

编译一个 TypeScript 文件:

tsc hello.ts 类型不匹配时,编辑报错,但可以生成js(编辑通过),如果不希望编译通过需要配饰tsconfig.json

发现在hello.ts同一目录下出现一个hello.js文件,这个文件就是ts编译器输出的内容,其中的js代码与编写的ts代码等价。

可用以下命令来运行:

        node hello.js

若想要把编译与运行结合起来,可使用ts-node模块:

    npm install -g ts-node
    ts-node hello.ts

类型:

原始数据类型:boolean、number、string、null、undefined、symbol、void、any

内置对象类型: Boolean Error Date RegExp Math Array

Document HTMLElementDiv Event MouseEvent NodeList

自定义类型:

class | interface


数值、字符串

let a:number=12;

let b:string = 'bmw’;


布尔值

let isDone: boolean = false;

NewBoolean: boolean = new Boolean(1);返回对象

null undefined 同理


空值

let unusable: void = undefined

function alertName(): void{}

注意:undefined 和 null 是所有类型的子类型,可以赋值给 number 类型的变量,而 void 类型的变量不能赋值给 number 类型的变量


任意值:

any 允许被赋值为任意类型,任何操作都返回任意值

let myFavoriteNumber: any = 'seven';

myFavoriteNumber = 7;


类型推论

没有明确的指定类型,依照值推断出一个类型。

let aa=12; //number 推论出为number类型

aa='qq';//无法修改


联合类型

取值可以为多种类型中的一种,没列出的不可以

let myFavoriteNumber: string | number;


对象类型:

依赖接口来描述,不给类型可以推论(原始数据类型和内置对象类型都没有object)


接口:

interface Person {

name: string;

age: number;

}

let p:Person={name:'xx',age:11}

注意:定义的变量比接口少了一些属性是不允许


可选属性: age?: number;

任意属性: [propName: string]: any; 任意值

注意:必填属性和可选属性都必须是任意属性的子属性

例如:[propName: string]: string 其他属性要是string子属性

只读属性: readonly id: number; 只能创建的时候被赋值


数组:

变量:类型[]:

let arr: number[] = [1, 1, 2, 3, 5];

let arr: any[] = [1, 1, 2, 3, 5];


Array<elemType>: 泛型 后面会单说

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


推荐:类型[ ] 这种方式;不然在tsx里有兼容问题


函数:

一个函数有输入和输出,进行约束,需要把输入和输出都考虑到

function sum(x: number, y: number): number {}

注意:输入多余的(或者少于要求的)参数,是不被允许的

函数表达式:

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

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

变量:输入类型=>输出类型=function(参数){}

可选参数: function buildName(a: string, b?: string) {}

注意:可选参数在后

参数默认值: lastName: string = ‘Liu'


接口中函数的定义:

interface SearchFunc {

(a: string, b: number): boolean;

}

let c: SearchFunc=function() {return true}

c('qq',11)


类型断言Assertion:

绕过编译器的类型推断,手动指定一个值的类型

<类型>值 (<string>something).length

值 as 类型 (something as string).length

注意:类型断言不是类型转换

在 tsx 语法(React 的 jsx 语法的 ts 版)中必须使用后者,即 值 as 类型。

用途:

将一个联合类型断言为其中一个类型

interface Cat {

name: string;

run(): void;

}

interface Fish {

name: string;

swim(): void;

}


function isFish(animal: Cat | Fish) {

if (typeof (animal as Fish).swim === 'function') {

return true;

}

return false;

}

需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误:

将一个父类断言为更加具体的子类

        class ApiError extends Error {

            code: number = 0;

        }

        class HttpError extends Error {

            statusCode: number = 200;    

        }

        function isApiError(error: Error) {

            if (typeof (error as ApiError).code === 'number') {

                return true;

            }

            return false;

        }

将任何一个类型断言为 any

但有的时候,我们非常确定这段代码不会出错,比如下面这个例子

window.foo = 1;

(window as any).foo = 1;

它极有可能掩盖了真正的类型错误,所以如果不是非常确定,就不要使用 as any


将 any 断言为一个具体的类型

在日常的开发中,我们不可避免地需要处理 any 类型的变量,它们可能是由于第三方库未能定义好自己的类型,也有可能是历史遗留的或其他人编写的烂代码,还可能是受到 TypeScript 类型系统的限制而无法精确定义类型的场景。

遇到 any 类型的变量时,我们可以选择无视它,任由它滋生更多的 any。

我们也可以选择改进它,通过类型断言及时地把 any 断言为精确的类型,亡羊补牢,使我们的代码向着高可维护性的目标发展。

        function getCacheData(key: string): any {

            return (window as any).cache[key];

        }

        interface Cat {

            name: string;        

            run(): void;

        }

        const tom = getCacheData('tom') as Cat;

        tom.run();


声明文件

ts 使用第三方库时,我们需要引用它的声明文件

ts 并不知道 $ 或 jQuery 是什么东西

declare 关键字来定义它的类型,帮助 TypeScript 判断我们传入的参数类型对不对

类型声明放到一个单独的文件中,这就是声明文件jQuery.d.ts

            declare var jQuery: (string) => any;

            jQuery('#div1');
    declare var jQuery: (string) => any;

   用到的文件的开头用「三斜线指令」表示引用了声明文件

        /// <reference path="./jQuery.d.ts" />

    安装第三方声明文件

        npm install @types/jquery --save-dev

    引入第三方方声明文件

        import * as jQuery from 'jquery';

        import * as $ from 'jquery';

用到的文件的开头用「三斜线指令」表示引用了声明文件

        /// <reference path="./jQuery.d.ts" />

    安装第三方声明文件

        npm install @types/jquery --save-dev

    引入第三方方声明文件

        import * as jQuery from 'jquery';

        import * as $ from 'jquery';


内置对象

        Boolean、Error、Date、RegExp,Math

            let b: Boolean = new Boolean(1);    大驼峰

        Document、HTMLElement、Event、NodeList

            let body: HTMLElement = document.body;

            let allDiv: NodeList = document.querySelectorAll('div');


类:

类(Class):定义了一件事物的抽象特点,包含它的属性和方法

对象(Object):类的实例,通过 new 生成

面向对象(OOP)的三大特性:封装、继承、多态

封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据


实例属性: 定义在类内部 name = 'Jack'; | public xx:string 定义在构造器内部 | get|set 属性(){}


继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性

es6: 使用 extends 关键字实现继承,子类中使用 super 关键字来调用父类的构造函数和方法

存取器(getter & setter):用以改变属性的读取和赋值行为

es6: 使用 get 属性(){return this._属性} 和 set 属性(val){this._属性=val} 可以改变属性的赋值和读取行为


静态方法: static 方法名(){} 类名.方法()

静态属性: static 定义在类内部 name = 'Jack'; ts实现了但转换到js暂不支持 调用:类名.方法()


访问修饰符(Modifiers):

修饰符是一些关键字,用于限定成员或类型的性质。比如 public 表示公有属性或方法

public:修饰的属性或方法是公有的,默认所有的属性和方法都是 public 的

private 修饰的属性或方法是私有的,不能在声明它的类的外部访问

protected 修饰的属性或方法是私有的+子类中允许访问

   public name: string;

            constructor(name: string)

            sayHi(): void{}

            p1: Person = new Person

接口:

可以用于对象的形状描述,函数的类型描述,类的行为进行抽象

思想:实现(implements)不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用 implements 关键字来实现

门是一个类,防盗门是门的子类。防盗门有一个报警器的功能,给防盗门添加一个报警方法。车内,也有报警器的功能,就可以考虑把报警器提取出来,作为一个接口,防盗门和车都去实现它

        interface Action{ 定义接口

            readonly id: number;//只读属性

            name:string;

            age?:number;可选

            [propName: string]: any;//任意属性

            eat?():string 可选方法的返回值

        }


实现(implements)。一个类只能继承自另一个类,但是可以实现多个接口

泛型:

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

    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']

上例中,我们在函数名后添加了 <T>,其中 T 用来指代任意输入的类型,在后面的输入 value: T 和输出 Array<T> 中即可使用了。

接着在调用的时候,可以指定它具体的类型为 string。当然,也可以不手动指定,而让类型推论自动推算出来:

createArray(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 {

    console.log(arg.length);

    return arg;

}

Tags:

最近发表
标签列表