TypeScript入门
搭建开发环境
安装TypeScript编译器 npm install -g typescript
一. 字符串新特性
...
的特性
1.多行字符串,这个将保存换行,空格
// index.ts
var content = `aaa
bbb
ccc
`
// index.js
var content = "aaa\nbbb\nccc";
2.字符串模板
index.ts
var myname = "xxx";
var getName = function () {
return "yyy";
}
console.log(`Hi ${myname}`);
console.log(`Hi ${getName()}`)
index.js
var myname = "xxx"
var getName = function () {
return "yyy";
}
console.log("Hi" + myname);
console.log("Hi" + getName());
3.自动拆分字符串
inedx.ts
function test(template, name, age) {
console.log(template); // ["hello my name is ", ", I am ", ""]
console.log(name); // xxx
console.log(age); // 18
}
var myname = "xxx"
var getAge = function () {
return 18;
}
test`hello my name is ${myname}, I am ${getAge()}`
index.js
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
return cooked;
};
function test(template, name, age) {
console.log(template);
console.log(name);
console.log(age);
}
var myname = "xxx";
var getAge = function () {
return 18;
};
test(__makeTemplateObject(["hello my name is ", ", I am ", ""], ["hello my name is ", ", I am ", ""]), myname, getAge());
二. 参数新特性
1. 参数类型
在变量, 方法, 方法参数后面使用冒号 : 来指定参数的类型
基本类型: string number boolean any void(方法的返回值) 自定义类型
// index.ts
var myname: string = "xxx";
myname = 13;
//
var myname = "xxx";
myname = 13;
注意:
- 这段代码只会在.ts文件中报错, 因为js没有类型检查
- ts参数没有冒号就会在第一次赋值的时候,确定类型
- 如果想赋值任何类型需要加 :
any
自定义类型:
class Person {
name: string;
age: number;
}
var zhangsan: Person = new Person()
zhangsan.name = "zhangsan"
zhangsan.age = 12
2. 参数默认值
在参数声明后面用等号来指定参数的默认值
// index.ts
function test(a: string, b: string, c: string = "dudu") {
console.log(a);
console.log(b);
console.log(c);
}
test("xxx", "yyy", "zzz");
test("xxx", "yyy");
注意: 带默认值的参数, 一定要声明在最后面
3. 可选参数
在方法的参数声明后面用问号来标注此参数为可选参数
// index.ts
function test(a: string, b?: string, c: string = "dudu") {
console.log(a); // xxx
console.log(b); //
console.log(c); // dudu
}
test("xxx");
注意: 可选参数必须在必选参数的后面
三. 操作符
1. Rest和Spread 操作符
...
可以向内传入任意个参数
// index.ts
function fun(...args) {
args.forEach(function (arg) {
console.log(arg)
});
}
fun(1, 2, 3);
fun(4, 5, 6, 7, 8);
// index.jsfunction fun() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
args.forEach(function (arg) {
console.log(arg);
});
}
fun(1, 2, 3);
fun(4, 5, 6, 7, 8);
...
还可以表示传入固定个参数
// index.ts
function fun(a, b, c) {
console.log(a);
console.log(b);
console.log(c);
}
var args = [1, 2]
fun(...args);
var arg = [1, 2, 3, 4, 5, 6]
fun(...arg)
// index.js
function fun(a, b, c) {
console.log(a);
console.log(b);
console.log(c);
}
var args = [1, 2];
fun.apply(void 0, args);
var arg = [1, 2, 3, 4, 5, 6];
fun.apply(void 0, arg);
注意: 这种写法在ts中报错, 但js中可以实现效果
3. generator函数
关键字 yield
控制函数的执行过程, 手工暂停和恢复代码执行
// index.ts
function* doSome() {
console.log("start");
yield;
console.log("finish")
}
var func = doSome();
func.next(); // start
func.next(); // finish
相当于打了一个断点, 在第一次调用
next()
方法时,到yield
暂停,再调用一次next()
才会向下执行
index.js
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
function doSome() {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("start");
return [4 /*yield*/];
case 1:
_a.sent();
console.log("finish");
return [2 /*return*/];
}
});
}
var func = doSome();
func.next();
func.next();
my.ts
function* getStockPrice(stock) {
while (true) {
// 返回一个0~100的数字
yield Math.random() * 100;
}
}
var priceGenerator = getStockPrice("CBM");
var limitPrice = 15; // 低于这个价格才会买
var price = 100; // 起始价格
while (price > limitPrice) {
// 调用函数, 返回数字, while继续判断
price = priceGenerator.next().value
console.log(`The generator return ${price}`)
}
console.log(`Buying at ${price}`)
my.js
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
function getStockPrice(stock) {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!true) return [3 /*break*/, 2];
// 返回一个0~100的数字
return [4 /*yield*/, Math.random() * 100];
case 1:
// 返回一个0~100的数字
_a.sent();
return [3 /*break*/, 0];
case 2: return [2 /*return*/];
}
});
}
var priceGenerator = getStockPrice("CBM");
var limitPrice = 15; // 低于这个价格才会买
var price = 100; // 起始价格
while (price > limitPrice) {
// 调用函数, 返回数字, while继续判断
price = priceGenerator.next().value;
console.log("The generator return " + price);
}
console.log("Buying at " + price);
4. destructuring解构表达式
通过表达式将对象或数组拆解成任意数量的变量
从对象中拆解
index.ts
function getStock() {
return {
code: "CBA",
price: {
price1: 99,
price2: 100
},
aaa: "dud"
}
}
// code: c 起别名
var {code: c, price: {price1} } = getStock();
console.log(c); // CBA
console.log(price) // 100
index.js
function getStock() {
return {
code: "CBA",
price: 99
};
}
var _a = getStock(), code = _a.code, price = _a.price;
从数组中拆解
my.ts
var array = [1, 2, 3, 4]
var [number1, number2, ...others] = array
function doSome([number1, number2, ...others]) {
console.log(number1); // 1
console.log(number2); // 2
console.log(others); // [3, 4]
}
doSome(array);
my.js
var array = [1, 2, 3, 4];
var number1 = array[0], number2 = array[1], others = array.slice(2);
function doSome(_a) {
var number1 = _a[0], number2 = _a[1], others = _a.slice(2);
console.log(number1);
console.log(number2);
console.log(others);
}
doSome(array);
四. 表达式和循环
1.箭头表达式
用来声明匿名函数, 消除传统匿名函数的
this
指针问题
index.ts
var myArray = [1, 2, 3, 4, 5];
console.log(myArray.filter(value => value % 2 == 0));
// index.js
var myArray = [1, 2, 3, 4, 5];
console.log(myArray.filter(function (value) { return value % 2 == 0; }));
注意: 方法只有一行可以省略括号和return, 参数只有一个可以省略括号
2.for in, for of
// for in
var myArray = [1, 2, 3, 4];
myArray.desc = "four number";
for (var i in myArray) {
console.log(i); // 1 2 3 4 desc
}
// for of
var myArray = [1, 2, 3, 4];
myArray.desc = "four number";
for (var i of myArray) {
if (n > 2) break;
console.log(i); // 1 2
}
for of
循环可以被打断,for in
不可以,for of
当参数为一个字符串时, 会将每一个字符打印出来
五. 类(class)
类是
TypeScript
的核心, 使用TypeScript开发时, 大部分代码都是写在类里的
1.定义: 用class
关键字和类名声明的
// index.ts
class Person {
name;
// 在用关键字new这个类的时候才会被调用一次, 不可以访问
constructor(name: string) { // 构造函数
console.log("haha")
this.name = name; // 表示声明时,必须初始化name
}
// 构造函数上没有默认控制符
// constructor(public name: string) { } 简化
age;
// pubic 访问控制符(默认) 内外都可以访问
// private 只有在类的内部才可以访问到
// protected 受保护的 可以在类的内部和类的子类被访问到
eat() {
console.log(this.name);
}
}
// extends 声明继承关系 继承类的所有属性和方法
class Emp extends Person{
constructor(name: string, code: string) {
// 子类的构造函数一定要调用父类的构造函数
super(name); // super 调用父类的构造函数
this.code = code
}
code: string;
work() {
super.eat() // super还可以调用父类的方法
this.doWork()
}
private doWork() { // 私有方法
console.log("work")
}
}
var e1 = new Emp("jing", "zhang");
var p1 = new Person("du");
p1.age = 19;
p1.eat();
var p2 = new Person("liu");
p2.age = 22;
p2.eat();
2.泛型 (generic)
参数化的类型, 一般用来限制集合的内容
// index.ts
// 指定数组只能用来放某一种类型的元素, 不能放其他类型的元素
var workers: Array<Person> = [];
workers[0] = new Person("zhang");
workers[1] = new Emp("liu", "du");
workers[2] = 2; // 报错
3. 接口 (Interface)
用来建立某种代码约定, 使得其他开发者在调用某个方法或创建新的类时必须遵循接口所定义的代码约定
①. 作为一个方法的参数的类型声明
interface IPerson {
name: string;
age: number;
}
class Person {
constructor(public config: IPerson) {} // 作为一个方法的参数的类型声明
}
var p1 = new Person({
name: "zhangsan",
age: 11
})
② 所有声明实现这个接口的类必须实现这个方法
interface Animal {
eat();
}
class Sheep implements Animal { // 所有声明实现这个接口的类必须实现这个方法
eat() {
console.log("I eat buf")
}
}
六. 模块 (Module)
模块可以帮助开发者将代码分割为可重用的单元.开发者可以自己决定将模块中的哪些资源(类, 方法,变量)暴露出去供外部使用,哪些资源只在内部使用
①export
导出 import
导入
//a.ts
export var prop;
var prop1;
export function func() {}
function fun2 () {}
export class Clazz() {}
class Clazz() {}
//b.ts
import {prop1, func, Clazz} from "./a"
console.log(prop1);
func();
new Clazz();
export function func3 () {}
②注解 (annotation)
注解为程序的元素(类, 方法, 变量)加上更直观明了的说明, 这些说明信息与程序的业务逻辑无关, 而是提供指定的工具或框架使用的
告诉一个框架如何处理一个类,如Angle
③类型定义文件 (*.d.ts
)
类型定义文件用来帮助开发者在TypeScript中使用已有的JavaScript的工具包, 如: jQuery
用.d.ts
结尾的文件 可以到GitHub的DEfinitelyTyped 里面有绝大部分的JS工具包