一、什么是TypeScript
TypeScript 是一种由微软开发的自由和开源的编程语言,它是 JavaScript 的一个超集,扩展了 JavaScript 的语法。
1,JavaScript VS TypeScript
a, TypeScript与JS的区别
TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。
TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译。
b,TypeScript相比JS的优势
· 优势一:类型化思维方式,使开发更加严谨,提前发现错误,减少改bug时间
· 优势二:类型系统提高了代码可读性,并使维护和重构代码更加容易
· 优势三:补充了接口、枚举等开发大型应用时JS缺失的功能
2,特性:
- 跨平台:TypeScript 编译器可以安装在任何操作系统上,包括 Windows、macOS 和 Linux
- ES6特性:TypeScript 包含计划中的 ECMAScript 2015(ES6)的大部分特性,例如:箭头函数
- 面向对象的语言:TypeScript 提供所有标准的 OOP 功能,如类、接口和模块
- 静态类型检查:TypeScript 使用静态类型并帮助在编译时进行类检查。因此,你可以在编写代码时发现编译时错误,而无需运行脚本
- 可选的静态类型:如果你习惯了 JavaScript 的动态类型,TypeScript 还允许可选的静态类型
- DOM、BOM操作:可以使用 Typescript 来操作 DOM 以添加或者删除客户端网页元素
let img = document.querySelector('#image') as HTMLImageElement
// 对于 DOM 以及 BOM的操作,建议使用 javascript
二、TypeScript 安装
// 需要安装提前安装npm
npm install -g typescript
//查看版本
tsc -v
// 如果需求编译时使用命令:tsc filename.ts
三、举个例子
1,创建项目文件夹tsDemo
2,新增一个html文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Learning TypeScript</title>
</head>
<body>
<script src="hello.js"></script>
</body>
</html>
3,新增一个ts文件
alert('hello world in TypeScript!');
4,编译这个ts文件
tsc hello.ts
5,双击tsDemo/index.html文件
四、基础知识
1,类型
ts的一大特色就是可以在不编译的情况下报错,就是因为她有类型批注这个功能,比如
// 基础数据类型批注
let isDone: boolean = false; // 布尔值
let decLiteral: number = 6; // 数字
let name: string = "bob"; // 字符串
let list: number[] = [1, 2, 3]; // 数组1
let list: Array<number> = [1, 2, 3]; // 数组2
let x: [string, number] = ['hello', 10]; // 元组
enum Color {Red, Green, Blue} // 枚举
let c: Color = Color.Green;
let notSure: any = 4; // 任意值
notSure = "maybe a string instead";
notSure = false;
function warnUser(): void { // 空值 void一般表示函数无返回值
alert("This is my warning message");
}
let u: undefined = undefined; // undefined类型
let n: null = null; // null类型
// Never类型
function error(message: string): never { // 返回never的函数必须存在无法达到的终点
throw new Error(message);
}
function fail() { // // 推断的返回值类型为never
return error("Something failed");
}
function infiniteLoop(): never { // 返回never的函数必须存在无法达到的终点
while (true) {
}
}
2,断言
当你遇到你比TypeScript更了解某个值的详细信息的时候。比如之前设置了any的值
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length; // 方法1
let strLength: number = (someValue as string).length; //方法2 :推荐,因为当你在TypeScript里使用JSX时,只有as语法断言是被允许的。
3,函数声明
type C = { a: string, b?: number }
function f({ a, b }: C): void {
// ...
}
4,接口
interface Point { // 混合类型
x: number; // 普通属性
readonly y: number; // 只读属性
color?: string; // 可选属性
reset(): void; //函数
}
// 函数类型
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
return result > -1;
}
// 索引类型
interface StringArray {
[index: number]: string;
}
// 接口继承
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
// 类类型,implements关键字用来实现类类型接口
interface ClockInterface {
currentTime: Date;
}
class Clock implements ClockInterface {
currentTime: Date;
constructor(h: number, m: number) { }
}
5,类
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number = 0) {
console.log(`${this.name} 移动 ${distanceInMeters}米.`);
}
}
class Snake extends Animal { // 作为派生类,通过extends关键字继承Animal类。
constructor(name: string) { super(name); }
move(distanceInMeters = 5) {
console.log("滑行中...");
super.move(distanceInMeters);
}
}
// 派生类包含了一个构造函数,它必须调用super(),
// 它会执行基类的构造函数。 而且,在构造函数里访问this的属性之前,我们一定要调用super()。
// 这个是TypeScript强制执行的一条重要规则。
class Horse extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 45) {
console.log("奔跑中...");
super.move(distanceInMeters);
}
}
let sam = new Snake("蛇三");
let tom: Animal = new Horse("马四");
sam.move();
tom.move(34);
// alert('hello world in TypeScript!');
class User {
static age = 23; // 静态属性,存在于类本身上,访问时不需要实例化
readonly id: number; // 可以访问,但是一旦确定不能修改
protected username: string; // 自身和子类可以访问,但是不能外部修改
private password: string; // 外部包括子类不能访问,也不可以修改
public info: string; // 默认的,可以去掉public修饰符
constructor(id: number, username: string, password: string, info: string) {
this.id = id;
this.username = username;
this.password = password;
this.info = info;
}
getInfo() {
console.log(this.id, `this.id`);
console.log(this.username, `this.username`);
console.log(this.password, `this.password`);
console.log(this.info, `this.info`);
}
//可以通过public方法修改private属性
setPassword(password: string) {
if (password.length >= 6) {
this.password = password;
}
}
}
class Vip extends User {
getInfo2() {
console.log(this.id, `this.id`);
console.log(this.username, `this.username`);
// console.log(this.password,`this.password`); //报错,私有类
console.log(this.info, `this.info`);
}
}
console.log(`User.age`,User.age);
let user1 = new User(1, '张三', '123456', '打工人');
user1.getInfo();
let vip = new Vip(1, '李四', '000000', '人上人');
vip.getInfo2();
console.log(user1.id, `user1.id;`);
// console.log(user1.username,`user1.username;`); // 报错,保护类 只有自身和子类可以访问
// console.log(user1.password,`user1.password;`); // 报错,私有类,只有自身可以访问
console.log(user1.info, `user1.info;`);
abstract class Department {
constructor(public name: string) {
}
printName(): void {
console.log('部门名称: ' + this.name);
}
abstract printMeeting(): void; // 必须在派生类中实现
}
class AccountingDepartment extends Department {
constructor() {
super('会计'); // 在派生类的构造函数中必须调用 super()
}
printMeeting(): void {
console.log('会计部门在每周一上午10点开会.');
}
generateReports(): void {
console.log('报告生成中...');
}
}
let department: Department; // 允许创建一个对抽象类型的引用
// department = new Department(); // 错误: 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
// department.generateReports(); // 错误: 方法在声明的抽象类中不存在
class Point {
x: number;
y: number;
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
6,函数
function add(x: number, y: number): number {
return x + y;
}
// 完整的函数类型定义
let myAdd: (x:number, y:number) => number =
function(x: number, y: number): number { return x + y; };
// 类型推断
let myAdd = function(x: number, y: number): number { return x + y; };
// 可选参数
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
let result1 = buildName("Bob"); // works correctly now
let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
let result3 = buildName("Bob", "Adams"); // ah, just right
// 默认参数
function buildName(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // works correctly now, returns "Bob Smith"
let result2 = buildName("Bob", undefined); // still works, also returns "Bob Smith"
let result3 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
let result4 = buildName("Bob", "Adams"); // ah, just right
// 剩余参数
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;
// 重载:为同一个函数提供多个函数类型定义来进行函数重载,根据参数不同调用不同函数
let suits = ["hearts", "spades", "clubs", "diamonds"];
function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; };
function pickCard(x): any {
// Check to see if we're working with an object/array
// if so, they gave us the deck and we'll pick the card
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
return pickedCard;
}
// Otherwise just let them pick the card
else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);
let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);
7,泛型
// 泛型函数
function identity<T>(arg: T): T {
return arg;
}
// 泛型接口
interface GenericIdentityFn<T> {
(arg: T): T;
}
// 泛型类
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
// 泛型约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); //扩展中表示参数是有length这个原型方法的
return arg;
}
let logs = loggingIdentity(['abc'])