TypeScript 简介

TypeScript是JavaScript的超集,提供静态类型系统以增强代码的可维护性和安全性。它包括多种数据类型如Boolean、Number、String、Array、Enum等,并支持类、接口、泛型等面向对象特性。此外,TypeScript还引入了对象解构、数组展开运算符、存取器、迭代器、模块和命名空间等功能,提高了代码的组织和复用性。
摘要由CSDN通过智能技术生成

官方文档

TypeScript是什么

TypeScript是由微软开发的,是JavaScript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程

安装 TypeScript

$ npm install -g typescript

编译 TypeScript 文件

$ tsc app.ts # app.ts => app.js

数据类型

  •  Boolean类型:
let isDone: boolean = false
  • Number 类型
let count:number = 10;
  • String 类型
let str:string = "hello";
  • Array 类型
let list:number[] = [1,2,3];

let list:Array<number> = [1,2,3]

数组解构

let x: number, let y: number ,let z: number;
let five_array = [0,1,2,3,4];
[x,y,z] = five_array;

数组展开运算符

let two_array = [0,1];
let five_array = [...two_array,2,3,4];

数组循环

let colors: string[] = ["red", "green", "blue"];
for(let i in colors) {
  console.log(i);
}
  • Enum (枚举)
enum Direction {
    NORTH,
    SOUTH,
    EAST,
    WEST
};

let dir:Direction = Direction.NORTH;
  • Any(动态类型)

有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any类型来标记这些变量:

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; 
  • Void

某种程度上来说,void 类型像是与 any 类型相反,它表示没有任何类型。当一个函数没有返回值时,你通常会见到其返回值类型是 void:

// 声明函数返回值为void
function warnUser(): void { 
    console.log("This is my warning message");
}

需要注意的是,声明一个 void 类型的变量没有什么作用,因为它的值只能为 undefined 或 null

let unusable: void = undefined;
  •  Null 和 Undefined

TypeScript里,undefinednull两者各自有自己的类型分别叫做undefinednull。 和 void相似,它们的本身的类型用处不是很大:

// Not much else we can assign to these variables!
let u: undefined = undefined;
let n: null = null;
  •  Tuple(元组类型)

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。比如,你可以定义一对值分别为 string 和 number 类型的元组。

let x:[string,number];
x = ['hello',10]; //正确赋值
x = [10,'hello']; // 不匹配
  • Never

never类型表示的是那些永不存在的值的类型。 例如, never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never类型,当它们被永不为真的类型保护所约束时。

  • Object

declare function create(o: object | null): void;

create({ prop: 0 }); // OK
create(null); // OK

对象解构

let person = {
  name: 'Semlinker',
  gender: 'male'
};

let {name, gender} = person;

对象展开运算符

let person = {
  name: 'Semlinker',
  gender: 'male',
  address: 'Xiamen'
};

// 组装对象
let personWithAge = {...person, age: 31};

// 获取除了某些项外的其它项
let {name, ...rest} = person;

 Assertion(类型断言)

通过类型断言这种方式可以告诉编译器,"相信我,我知道自己在干什么"。类型断言好比其他语言里的类型转换,但是不进行特殊的数据检查和解构。它没有运行时的影响,只是在编译阶段起作用。

类型断言有两种形式。

类型断言有两种形式。

  • “尖括号”语法:
let someValue:any = 'this is a string';
let strLength:number = (<string>someValue).length;
  • as语法:
let someValue: any = "this is a string";
let strLength:number = (someValue as string).length;

注:当你在TypeScript里使用JSX时,只有 as语法断言是被允许的。

变量声明

let ,const  代替var ,这个es6中已经使用,这里不再赘述。

Interface(接口)

在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implements)。

TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。

  • 对象类型
interface Person {
  name: string;
  age: number;
}

let semlinker: Person = {
  name: 'Semlinker',
  age: 31
};

可选 | 只读属性

interface Person {
  readonly name: string; //只读属性
  age?: number; // 可选属性
}
  • 函数类型
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 ClockInterface {
    currentTime: Date;
    setTime(d: Date);
}

class Clock implements ClockInterface {
    currentTime: Date;
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) { }
}

Class(类)

详情见:类 · TypeScript中文网 · TypeScript——JavaScript的超集

class Greeter {
   static cname: string = 'Greeter'; // 静态属性
   greeting: string; // 成员属行

   constructor(message: string) { // 构造函数 - 执行初始化操作
     this.greeting = message;
   }

    static getClassName() { // 静态方法
      return 'Class name is Greeter';
    }
    
    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} moved ${distanceInMeters}m.`);
    }
}

class Snake extends Animal {
    constructor(name: string) { super(name); }
    move(distanceInMeters = 5) {
        console.log("Slithering...");
        super.move(distanceInMeters);
    }
}

class Horse extends Animal {
    constructor(name: string) { super(name); }
    move(distanceInMeters = 45) {
        console.log("Galloping...");
        super.move(distanceInMeters);
    }
}

let sam = new Snake("Sammy the Python");
let tom: Animal = new Horse("Tommy the Palomino");

sam.move();
tom.move(34);

存取器

TypeScript支持通过getters/setters来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。

let passcode = "secret passcode";

class Employee {
    private _fullName: string;

    get fullName(): string {
        return this._fullName;
    }

    set fullName(newName: string) {
        if (passcode && passcode == "secret passcode") {
            this._fullName = newName;
        }
        else {
            console.log("Error: Unauthorized update of employee!");
        }
    }
}

let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
    alert(employee.fullName);
}

对于存取器有下面几点需要注意的:

首先,存取器要求你将编译器设置为输出ECMAScript 5或更高。 不支持降级到ECMAScript 3。 其次,只带有 get不带有 set的存取器自动被推断为 readonly。 这在从代码生成 .d.ts文件时是有帮助的,因为利用这个属性的用户会看到不允许够改变它的值。

Generics(泛型)

泛型(Generics)是允许同一个函数接受不同类型参数的一种模板。相比于使用 any 类型,使用泛型来创建可复用的组件要更好,因为泛型会保留参数类型。

  • 泛型接口

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);  // Now we know it has a .length property, so no more error
    return arg;
}

现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:

loggingIdentity(3);  // Error, number doesn't have a .length property

//我们需要传入符合约束类型的值,必须包含必须的属性:

loggingIdentity({length: 10, value: 3});

函数

  • 箭头函数
myBooks.forEach(() => console.log('Done reading'));

myBooks.forEach(title => console.log(title));

myBooks.forEach((title, idx, arr) => 
  console.log(idx + '-' + title);
);
  • 参数类型和返回类型
function createUserId(name: string, id: number): string {
  return name + id;
}
  • 函数类型
let IdGenerator: (chars: string, nums: number) => string;

function createUserId(name: string, id: number): string {
  return name + id;
}

IdGenerator = createUserId;
  • 可选参数及默认参数
// 可选参数
function createUserId(name: string, age?: number, 
  id: number): string {
    return name + id;
}

// 默认参数
function createUserId(name: string = 'Semlinker', age?: number, 
  id: number): string {
    return name + id;
}
  • 剩余参数
function push(array, ...items) {
  items.forEach(function(item) {
    array.push(item);
  });
}

let a = [];
push(a, 1, 2, 3);

 迭代器

  • for..of vs. for..in 语句

for..offor..in均可迭代一个列表;但是用于迭代的值却不同,for..in迭代的是对象的  的列表,而for..of则迭代对象的键对应的值。

let list = [4, 5, 6];

for (let i in list) {
    console.log(i); // "0", "1", "2",
}

for (let i of list) {
    console.log(i); // "4", "5", "6"
}

另一个区别是for..in可以操作任何对象;它提供了查看对象属性的一种方法。 但是 for..of关注于迭代对象的值。

let pets = new Set(["Cat", "Dog", "Hamster"]);
pets["species"] = "mammals";

for (let pet in pets) {
    console.log(pet); // "species"
}

for (let pet of pets) {
    console.log(pet); // "Cat", "Dog", "Hamster"
}

module and namespace (模块和命名空间)

  • 模块

请务必注意一点,TypeScript 1.5里术语名已经发生了变化。 “内部模块”现在称做“命名空间”。 “外部模块”现在则简称为“模块”,这是为了与 ECMAScript 2015里的术语保持一致,(也就是说 module X { 相当于现在推荐的写法 namespace X {)。

模块在其自身的作用域里执行,而不是在全局作用域里;这意味着定义在一个模块里的变量,函数,类等等在模块外部是不可见的,除非你明确地使用export形式之一导出它们。 相反,如果想使用其它模块导出的变量,函数,类,接口等的时候,你必须要导入它们,可以使用 import形式之一。

模块是自声明的;两个模块之间的关系是通过在文件级别上使用imports和exports建立的。

模块使用模块加载器去导入其它的模块。 在运行时,模块加载器的作用是在执行此模块代码前去查找并执行这个模块的所有依赖。 大家最熟知的JavaScript模块加载器是服务于Node.js的 CommonJS和服务于Web应用的Require.js

TypeScript与ECMAScript 2015一样,任何包含顶级import或者export的文件都被当成一个模块。相反地,如果一个文件不带有顶级的import或者export声明,那么它的内容被视为全局可见的(因此对模块也是可见的)。

  • 命名空间

内部模块”现在叫做“命名空间”。 另外,任何使用 module关键字来声明一个内部模块的地方都应该使用namespace关键字来替换。

命名空间 · TypeScript中文网 · TypeScript——JavaScript的超集

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值