学习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 运行,具体方法可以查看我的另一篇文章

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

Typescript 中文官方文档:

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 参数默认值

  1. 可选参数要声明在必选参数后面
  2. 有默认值得参数要放在参数的最后面
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 (或全局)对象。详细可参考

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

访问权限关键字:

  1. public 公共成员(默认)。 子类、父类内部都可以访问到。
  2. private 私有成员。只允许在类中访问。
  3. 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 ,其它的则不会被包含进来。