学习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 ,其它的则不会被包含进来。