为什么使用Typescript?
微软推出TypeScript主要是为实现两个目标:
- 为Javascript提供可选的类型系统;
- 兼容当前及未来的JavaScript的特性。
静态类型带来的好处:
- 有利于代码重构,它在编译器编译的时候就能捕获错误。
- 类型明确有利于阅读。
JavaScript常见语法
TypeScript是JavaScript的“超集”,typescript将javascript语法标准化。
-
== 与 ===
使用==进行比较时,会进行隐式转换。
2 == 2 true
2 == '2' true
2 === '2' false
-
引用
除字面量外,JavaScript中的任何对象(包括函数、数组、正则表达式等)都是一个引用。
-
null和undefined
变量没有初始化:undefined。变量不可用为null。
undefined == undefined true
undefined == null true
// 检查变量是否初始化
if( typeof val !== 'undefined'){}
-
this
this关键字指向调用上下文
function foo(){console.log(this)} /** this --> window **/
var obj = {foo:function(){console.log(this)}}
obj.foo() /** this --> obj */
-
闭包
内部函数访问外部变量,此时外部函数的变量被内部函数绑定,称为闭包。
function outer(){
var outerVal = '1'
function inner(){
console.log(outerVal)
}
outer()
}
/** inner 绑定了 outerVal */
-
数字
JavaScript中数值是双精度的64位的number
console.log(.1 + .2) // 0.30000000000000004
内置整数类型限制 Number.MAX_SAFE_INTEGER-Number.MIN_SAFE_INTEGER
金融计算中一般使用 big.js
NaN,计算出的结果不是合法数值时返回NaN,检测NaN,Number.isNaN。
-
thuthy
!!双感叹号,第一个!是将值转为布尔值,第二个逻辑反转。
ES6语法
-
class
/*ES6*/
class Point {
x: number
y: number
constructor(x: number, y: number) {
this.x = x
this.y = y
}
add(point: Point) {
return new Point(this.x + point.x, this.y + point.y)
}
}
/*编译后ES5*/
var point = function(){
function Point(x, y){
this.x = x;
this.y = y;
}
Point.prototype.add = function(point){
return new Point(this.x + point.x, this.y + point.y)
}
return Point;
}()
继承
/*ES6*/
class Point3D extends Point {
z: number
constructor(x: number, y: number, z: number) {
super(x, y)
this.z = z
}
add(point: Point3D) {
var point2D = super.add(point)
return new Point3D(this.x + point2D.x, this.y + point2D.y, this.z + point.z)
}
}
/*编译后ES5*/
var point3D = function(_super){
__extends(Point3D, _super)
function Point3D(x, y, z){
_super.call(this, x, y)
this.z = z;
}
Point3D.prototype.add = function(point){
var point2D = _super.prototype.add.call(this, point)
return new Point3D(this.x + point2D.x, this.y + point2D.y, this.z + point.z)
}
return Point;
}(Point)
/**__extends typescript 编译 extends 时生成*/
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
/*
d表示派生类,b表示基类
*/
return function (d, b) {
extendStatics(d, b); // 拷贝静态变量
function __() { this.constructor = d; } // 保留派生构造器
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); //d.prototype.__proto__ = b.prototype
};
})();
区分 __ proto __ prototype
javascript 中所有对象都有属性__ proto __
/** 查找属性顺序
obj.property
obj.__proto__.property
obj.__proto__.__proto__.property
**/
javasript 所有的函数都有属性 prototype,prototype有个指向函数本身的构造器constructor。
function Foo(){
this.name = "xm"
}
var foo = new Foo();
/**通过函数创建的对象,会将函数prototype传给对象__proto__*/
console.log(foo.__proto__ === Foo.prototype)
-
箭头函数
var inc = x => x + 1;
箭头函数带来语法简洁和this丢失问题。
-
rest参数
...+参数名的形式表示最后一个参数,获取时转为数组。
-
let和const
var 变量是函数作用域,let 变量块作用域
/**闭包中的var*/
var funcs = []
for(var i = 0;i < 3; i++){
funcs.push(function(){
console.log(i)
})
}
for(var j = 0;j < 3; j++){
funcs[j]();
}
/*输出 3*/
const 声明常量值。
-
解构
支持对象和数组解构。
/*对象解构*/
var person = {name:'x',age:12,gender:1}
var {name, age} = person
console.log(name, age) // x, 12
var {x, y, ...remaining} = {x: 1, y: 2, z: 4, w: 5} // 看作删除了x,y
console.log(x,y,remaining) // 1,2 {z:4,w:5}
-
扩展运算符
Function.prototype.apply
/*apply调用*/
function foo(x,y){}
var args = [0,1]
foo.apply(null, args)
// 新语法
foo(...args)
// 数组追加元素
var list = [1, 2]
list = [...list, 3] // [1,2,3]
list = [0,...list,4] // [0,1,2,3,4]
-
for...of
/*for...in*/
for(var e in [7,8,9]){console.log(e) }// 返回索引
for(var e of [7,8,9]){console.log(e) }// 返回元素
-
Promise
使用Promise处理异步和回调函数。
var promise = new Promise((resolve, reject) => {resolve()//回调正确值
reject() // 异常值
})
promise.then(res => {}) // 正常
.catch(err => {}) // 异常
并行流程控制,Promise.all([promise1,promise2]).then(res => [result1, result2])
-
generators
function* idGen(){
let index = 0
while(index < 3) yield /*暂停*/ index++;
}
var id = idGen();
console.log(id.next());
console.log(id.next());
console.log(id.next());
console.log(id.next());
-
async/await
async function foo(){
var result = await exPromise() //等待promise执行返回
console.log(result)
}
TS项目构成
-
编译上下文
tsconfig.json配置文件,配置选项:tsconfig
-
声明空间
类型声明空间和变量声明空间。
-
类 (class): 类型, 值.
-
接口 (interface): 类型.
-
枚举 (enum): 类型, 值.
-
类别名 (type): 类型.
-
函数 (function): 值.
-
变量 (let, const, var, parameters): 值.
-
模块
默认情况下声明处于全局命名空间中。使用export变成文件模块。
模块路径查找
/**相对路径**/
import * as foo from './foo' // 同级目录
import * as foo from '../foo' // 上级目录
import * as foo from '../someFolder/foo // 相对目录
/**导入路径不是相对路径时,动态查找**/
import * as foo from 'foo'
/*
查找顺序
./node_modules/foo
../node_modules/foo
../../node_modules/foo
*/
import * as foo from 'something/foo'
/**
./node_modules/something/foo
../node_modules/something/foo
../../node_modules/something/foo
*/
/* place */
import * as foo from 'foo'
/**查找顺序*/
/**
foo 是文件 foo.ts
foo 是目录 foo/index.ts
foo 是目录 foo/package.json 有 types
foo 是目录 foo/package.json 有 main
**/
-
命名空间
//typescript 声明
namespace Utility {
export function log(msg) {
console.log(msg);
}
export function error(msg) {
console.log(msg);
}
}
// usage
Utility.log('Call me');
Utility.error('maybe');
var Utility;
(function (Utility) {
function log(msg) {
console.log(msg);
}
Utility.log = log;
function error(msg) {
console.log(msg);
}
Utility.error = error;
})(Utility || (Utility = {}));
// usage
Utility.log('Call me');
Utility.error('maybe');
-
动态导入表达式
// 动态加载
import(/* webpackChunkName: "momentjs" */ 'moment')
.then(moment => {
// 懒加载的模块拥有所有的类型,并且能够按期工作
const time = moment().format();
console.log('TypeScript >= 2.4.0 Dynamic Import Expression:');
console.log(time);
})
.catch(err => {
console.log('Failed to load moment', err);
});
创建TS项目
- 安装node环境,创建目录进入执行 npm init -y;
- 安装ts npm install typescript --save-dev ;
- 创建文件 node.d.ts npm install @types/node --save-dev;
- 初始化tsconfig.json npx tsc --init --rootDir src --outDir lib --esModuleInterop --resolveJsonModule --lib es6 , dom --module commonjs;
- 添加ts-node:npm install ts-node --save-dev 实现实时编译和运行;
- 添加nodemon:npm install nodemon --save-dev,只要文件被改变,它就会调用ts-node。
TS类型系统
-
基本概念
基本类型 number string boolean string[]
接口 interface
特殊类型 any、null、undefined和void
// 接口
interface Name{
first: string,
last: string
};
let n : Name;
n = {
first: 'Li',
last:'p'
}
// 泛型
function contact<T>(items : T[]): T[]{
//......
return items;
}
// 联合类型
function join(items : string[] | string){
//......
}
// 交叉类型
function extend<T, U>(first: T, last : U) :T & U{
const result = <T & U>{}
return result
}
// 元祖类型
let nameNum : [string, number]
//类型别名
type mind = string | Number
let m : mind
-
@types
仓库 @types 通过配置tsconfig.json的compilerOptions.types控制全局。
-
环境声明
使用关键字declare进行声明,一般放在.d.ts文件。
-
枚举
数字枚举和字符串枚举。
-
lib.d.ts
安装TypeScript时,会顺带安装一个lib.d.ts声明文件。这个文件包含JavaScript运行时及DOM(Document Object Model,文档对象模型)中存在的各种常见的JavaScript环境声明。
-
函数
声明函数 type inc = (num : number) => number
-
可调用可实例化
// 可调用
interface ReturnStr{
() : string;
}
declare const foo : ReturnStr
const str = foo() // str 字符串
// 内联注解
const overload: {
(foo: string): string;
(foo: number): number;
} = (foo: any) => foo
// 可实例化
interface NewAble {
new (): string;
}
declare const newAble: NewAble;
const foo = new newAble
-
类型断言
Ts可以以任何方式去重写其推断和分析的类型,称为类型断言。
interface Foo{
Bar : string
}
const f1 = {} as Foo;
f1.bar = "1";
const f2 = <Foo>{};
f2.bar = "2";
-
Freshness
检查字面量类型
function hasName(some: { name: string }) {
some.name = "name"; // 正确
some.age = 12; // 错误
}
-
类型保护
typeof (typeof x === 'string')
instanceof (foo instanceof Foo)
in 检查对象是否存在对应属性
-
readonly
type Foo = {
readonly bar: string;
};
const f: Foo = { bar: "x" };
f.bar = "y"; // 错误,不可修改
-
泛型
类的实例成员、类的方法、函数的参数、函数返回值之间的约束。
-
never
never类型就是TypeScript中的底部类型。用于一个总会抛出错误的函数或一个总会抛出错误的函数。
never与void的差异,void表示没有任何类型,never表示永远不存在的值的类型。
-
异常处理
try {
throw new Error("err.");
} catch (error) {
console.log(error)
}
代码风格约定
-
使用camelCase形式为变量和函数命名。
-
使用PascalCase形式为类命名。
-
使用PascalCase形式为接口命名。
-
类型别名使用PascalCase形式进行命名。
-
命名空间使用PascalCase形式进行命名。
-
枚举类型使用PascalCase形式进行命名。
-
对于需要明确表明不可用的情况,null和undefined都不建议使用。
-
格式化
tsfmt命令格式化,使用单引号,空格两tab,如果想用extends或implements,则建议使用interface。
TS编译原理
.....待续再看
|
请发表评论