TypeScript 学习笔记

mac2024-05-31  36

学习Typescript 之前 要搞清楚 javascript typescript es6 三者的关系

ES6是什么

ECMAScript 6.0(以下简称ES6)是JavaScript语言(现在是遵循ES5标准)的下一代标准,已经在2015年6月正式发布了。它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

ECMAScript和JavaScript的关系

由于JavaScript的创造者Netscae公司的版权问题,ECMAScript不能叫Javascript。总之,ECMAScript和JavaScript的关系是,前者是后者的规格(语言规范),后者是前者的一种实现。

JavaScript 与 TypeScript 的关系

TypeScript是Javascript的超集,实现以面向对象编程的方式使用Javascript。当然最后代码还是编译为Javascript。

TypeScript和ES6的关系

TypeScript是ES6的超集。至于需不需要使用,在于你所需要的场景。比如在Angular2中,用TypeScript明显好于ES6。

总结一下: ES6是Javascript语言的标准,typescript是ES6的超集,Angular2是基于typescript来开发的JS框架。

Typescript 代码最后需要转换成 javascript 运行,具体方法可以查看我的另一篇文章 VScode 自动编译TypeScript的配置

下面是我自己总结精简的一些入门的知识点,基本够用,大家要是想详细的学习 typescript 或者查阅一些知识点可以去看官方文档

Typescript 中文官方文档:https://www.tslang.cn/docs/handbook/basic-types.html

1. 基础类型检测 Basic Types Test

1、ts针对变量、方法,以及方法参数的类型声明及类型检测报错,并不会影响实际编译后的js;

2、方法的类型声明有3种情况,可以给接收的参数声明类型(当调用该方法时传入的实参做类型检测)也可以给方法声明类型(对该方法的return返回值做类型检测),亦或者将该方法类型声明为void类型(不需要任何返回值)。

下面是实际操作

// 1. boolean值 var a: boolean = true; // 2. number数字 var a: number= 1; // 3. string字符串 var a: string = "LOKKA"; // 4. number数组 // 等价声明 var arr: number[] = [1, 2, 3]; let arr: Array<number> = [1, 2, 3]; // 4. string数组 let arr: string[] = ["a", "b", "c"]; // 5. 元组 var a: [string, number] = ['hello', 10]; // OK; // 6. 枚举 enum Color {Red, Green, Blue} var c: Color = Color.Green; // 7. 任意类型 var a: any = 1; // 7. 任意类型数组 var list: any[] = [1, true, "free"]; // 8. 没有类型 只能是null 或 undefined var a: void = undefined;var a: void = 1; × // 9. Null 和 Undefined let value: null = null; let num: number = value; console.log(num + 1); //输出 1 // 10. Never 不会有返回类型,死循环和报错 // 返回never的函数必须存在无法达到的终点 function error(message: string): never { throw new Error(message); } // 11. Object——————除number,string,boolean,symbol,null或undefined之外的类型 declare function create(o: object | null): void; create({ prop: 0 }); // OK create(null); // OK
函数参数

?可选参数 c: number = 1 参数默认值

可选参数要声明在必选参数后面有默认值得参数要放在参数的最后面 function test(a: string, b?: string, c: number = 1) { console.log(a, b, c); } test("aa");

2. 字符串新特性

// 跟 ES6 一样 通过 `` 拼接 let a = `<a> <span>hello world!</span> <a/>`; // 编译为 js 后 var a = "<a>\n<span>hello world!</span>\n<a/>"; let a = "lokka"; console.log(hello ${a}!; // 编译为 js 后 var a = "lokka"; console.log("hello " + a + "!"); // hello lokka!

3. 变量声明

因为TypeScript是JavaScript的超集,所以它本身就支持let和const。

4. 解构赋值 Destructuring

和 es6 用法差不多

// 数组结构赋值: let [a, ...b] = [1, 2, 3, 4]; console.log(a); console.log(b); // 对象解构赋值 let obj = { a: "1", b: "2", c: "3", d: "4" } let {a,...b} = obj; console.log(b);

5. Generator 函数

// 声明方式 * function* test() { console.log("111"); // 断点 yield; console.log("222"); } // test()并不会执行test函数,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是迭代器对象(Iterator Object); var a = test(); a.next(); // 111 a.next(); // 222

6. 箭头函数

作用一:主要用于声明匿名函数,简化代码。

var sum = (a,b)=>a+b 上式等价于: var sum = function (a,b){ retrun a+b; };

作用二:消除this指针带来的歧义,优化执行上下文。

function test() { var a = 1; setTimeout(function () { console.log(this.a); },1000) } test(); // undefined

这是由于setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。这会导致这些代码中包含的 this 关键字会指向 window (或全局)对象。详细可参考MDN setTimeout

for…of 和 for…in语句

for…of和for…in均可迭代一个列表;但是用于迭代的值却不同,for…in迭代的是对象的 键 的列表,而for…of则迭代对象的键对应的值。

for(let i of ['a','b','c']) //i遍历是 'a','b','c' for(let i in ['a','b','c']) //i遍历是 0,1,2

7. interface 接口

interface是一种类型,预先定义好一系列的属性的类型,然后供新的对象来使用它。

// 描述对象 interface New { name: string, age: number } function foo(config: New) { console.log(config.name); } var a = new foo({ // 必须所有属性都具备 name: "lokka", age: 18 }) // 描述函数类型 它就像是一个只有参数列表和返回值类型的函数定义 interface SearchFunc { (source: string, subString: string): boolean; } // 这样定义后,我们可以像使用其它接口一样使用这个函数类型的接口。 下例展示了如何创建一个函数类型的变量,并将一个同类型的函数赋值给这个变量。 let mySearch: SearchFunc; mySearch = function(source: string, subString: string) { let result = source.search(subString); return result > -1; } // 对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配。 比如,我们使用下面的代码重写上面的例子: let mySearch: SearchFunc; mySearch = function(src: string, sub: string): boolean { let result = src.search(sub); return result > -1; }

8. 基于Class的继承

class New { // 类内部变量 a a = "lokka"; // 类内部方法 test() test() { console.log("111"); } // 构造器 // 在构造器中,相当于新建了一个局部的作用域,在构造器中声明的变量、属性都是局部的,哪怕是在Class内部、构造器之外,也无法访问 constructor() { console.log("222"); } } var foo = new New(); // new 出实例 通过原型链继承 console.log(foo.a); // lokka console.log(foo.test()); // 111

访问权限关键字:

public 公共成员(默认)。 子类、父类内部都可以访问到。private 私有成员。只允许在类中访问。protected 超类的私有成员。但是在子类中仍然可以访问。 class New { // 类内部变量 a public a = "lokka"; // 类内部方法 test() private test() { console.log("111"); } } var foo = new New(); // new 出实例 通过原型链继承 console.log(foo.a); // lokka console.log(foo.test()); // Property 'test' is private and only accessible within class 'New'.

9. 泛型 Generic

参数化的类型,一般用来限制集合的内容

使用尖括号<>定义泛型

泛型用来指定只能放某一类型的元素,不能放其它类型的元素

function identity<T>(arg: T): T { return arg; }

我们给identity添加了类型变量T。 T帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。 第一种是,传入所有的参数,包含类型参数:

let output = identity<string>("myString"); // type of output will be 'string'

这里我们明确的指定了T是string类型,并做为一个参数传给函数,使用了<>括起来而不是()。

第二种方法更普遍。利用了类型推论 – 即编译器会根据传入的参数自动地帮助我们确定T的类型:

let output = identity("myString"); // type of output will be 'string'

10. 接口interface

interface:用于规定类的参数的类型(我们传入的对象参数实际上会包含很多属性,但是编译器只会检查那些必需的属性是否存在,并且其类型是否匹配)

interface LabelledValue { label: string; } function printLabel(labelledObj: LabelledValue) { console.log(labelledObj.label); } let myObj = {size: 10, label: "Size 10 Object"}; printLabel(myObj);

implements: 实现某接口的类,必须实现该接口里的方法

与C#或Java里接口的基本作用一样,TypeScript也能够用它来明确的强制一个类去符合某种契约。

interface ClockInterface { currentTime: Date; } class Clock implements ClockInterface { currentTime: Date; constructor(h: number, m: number) { } }

你也可以在接口中描述一个方法,在类里实现它,如同下面的setTime方法一样:

interface ClockInterface { currentTime: Date; setTime(d: Date); } class Clock implements ClockInterface { currentTime: Date; setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number) { } }

11. 模块Modules

模块在其自身的作用域里执行,而不是在全局作用域里;这意味着定义在一个模块里的变量,函数,类等等在模块外部是不可见的,除非你明确地使用export形式之一导出它们。 相反,如果想使用其它模块导出的变量,函数,类,接口等的时候,你必须要导入它们,可以使用import形式之一。

export:
// a.ts export function area(radius) { return Math.PI * radius * radius; } export function circumference(radius) { return 2 * Math.PI * radius; }
import:
// b.ts import { area, circumference } from './hello'; console.log('圆面积:' + area(4)); console.log('圆周长:' + circumference(14));

12. 类型定义文件(*.d.ts)

类型定义文件用来帮助开发者在 Typescript 中使用已有的 JavaScript 的工具包 如: jQuery

@Types

使用另外一套系统来管理类型定义显然不太方便。 在 Typescript 2.0 之后,TypeScript 将会默认的查看 ./node_modules/@types 文件夹,自动从这里来获取模块的类型定义,当然了,你需要独立安装这个类型定义。 比如,你希望 jquery.js 的类型定义,那么,你需要安装这个库的定义库。

npm install --save @types/jquery

与我们安装一个普通的库没有区别。当然了,常用的 jquery 也有。Microsoft 在 The Future of Declaration Files 介绍了 TypeScript 的这个新特性。 默认情况下,所有的 @types 包都会在编译时应用,任意层的 node_modules/@types 都会被使用,进一步说,在

**./node_modules/@types/ ,../node_modules/@types/ **, **../../node_modules/@types/ **

都被应用。 如果你的类型定义不在这个文件夹中,可以使用 typesRoot 来配置,只有在 typeRoots 中的包才会被包含,例如:

{ "compilerOptions": { "typeRoots" : ["./typings"] } }

现在,只有在 ./typings 中的才会应用,而 ./node_modules/@types 中的则不会。 如果配置了 types,则只有列出的包才会包含。

{ "compilerOptions": { "types" : ["node", "lodash", "express"] } }

这样将只会包含 ./node_modules/@types/node, ./node_modules/@types/lodash 和 ./node_modules/@types/express ,其它的则不会被包含进来。

最新回复(0)