TypeScript介绍
- TypeScript是JavaScript类型的超集,它可以编译成纯JavaScript。
- TypeScript可以在任何浏览器、任何计算机和任何操作系统上运行,并且是开源的。
为什么要用TypeScript
- TypeScript简化了JavaScript代码,使其更易于阅读和调试。
- TypeScript是开源的。TypeScript为JavaScript IDE 和实践提供了高效的开发工具,例如静态检查。
- TypeScript使代码更易于阅读和理解。使用TypeScript,我们可以比普通的JavaScript做出巨大的改进。
- TypeScript为我们提供了ES6(ECMAScript 6)的所有优点,以及更高的工作效率。
- TypeScript可以帮助我们避免开发人员通过类型检查代码编写JavaScript时经常遇到的痛苦错误。强大的类型系统,包括泛型。
- TypeScript只是带有一些附加功能的JavaScript。结构,而不是名义上的。
- TypeScript代码可以按照ES5和ES6标准进行编译,以支持最新的浏览器。与ECMAScript对齐以实现兼容性。以JavaScript开始和结束。支持静态类型。
- TypeScript将节省开发人员的时间。TypeScript是ES3,ES5和ES6的超集。
使用TypeScript
npm install typescript -g
tsc --version
- 新建一个文件夹,并使用
npm init -y
初始化。 - 在终端中输入tsc --init:创建tsconfig.json文件,它是一个TypeScript项目的配置文件。
- 编写一个
index.ts
,输入下面代码
let name: string = 'detanx'
console.log('name', name)
- 然后在终端中运行
tsc index.ts
,会在当前文件夹下生成一个index.js,使用node index.js会看到打印的结果。
声明文件
- 当使用第三方库时,我们需要引用它的声明文件
声明语句
- 假如我们想使用第三方库,例如jQuery,我们通常这样获取一个元素
jQuery('#id')
// index.ts(1,1): error TS2304: Cannot find name jQuery
declare var jQuery:(selector: string) =>any;
jQuery('#id')
- declare定义的类型只会在编译的时候检查,编译后会删除
声明文件
- 把声明的类型放在一个单独的文件中,这就是声明文件
// jQuery.d.ts
declare var jQuery:(selector: string) =>any;
- 声明文件的结尾约定为
.d.ts
- 在使用的文件最开头使用三斜线指令引入
- 三斜线指令是包含单个XML标签的单行注释。 注释的内容会做为编译器指令使用。
- 三斜线指令仅可放在包含它的文件的最顶端。 一个三斜线指令的前面只能出现单行或多行注释,这包括其它的三斜线指令。 如果它们出现在一个语句或声明之后,那么它们会被当做普通的单行注释,并且不具有特殊的涵义。
/// <referrence path='./jQuery.d.ts' />
jQuery('#id')
第三方声明文件
- 现在很多库都有自带的第三方声明文件,
@types/包名
npm install @types/jquery --save-dev
TypeScript中的数据类型
- undefined : undefined类型,定义了一个变量,但没有给他赋予任何值
let name: undefined
- null :空类型,一个值为空
let name: null = null
- number:数值类型,数值类型,包括整数、浮点、NaN、Infinity、-Infinity
let age: number = NaN
- string : 字符串类型,由单引号或者双引号括起来的一串字符
let str: string = 'detanx'
- boolean: 布尔类型,boolean类型只有两种值,true和false。
let isMan: boolean = true
- enum:枚举类型,已知几个数据的对应关系
enum PEOPLE{ man , woman }
- any : 任意类型,即可以赋值为任意的数据类型
let anyType: any = 'string'
anyType = 1
...
- Tuple: 元组,合并了不同类型的对象
let people: [string, number]
people[0] = 'detanx'
people[1] = 12
- ......
类型声明场景
- 多类型,使用
|
分割
let age: number | string = '18'
age = 19
- 可选属性,使用
?
interface IPerson<T> {
name: string
age?: number
}
- 未知/额外属性
interface IPerson<T> {
name: string
age?: number
[propName: string]: any; // 额外任意属性
}
- 数组的声明方式
let array = string[] // 元素类型后跟上[],字符串数组
let arrat = Array<string> // 数组泛型
- 可索引类型
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0];
函数声明
- 声明方式
// 函数声明
function getName(name: string):string {
return name
}
// 函数表达式
const getName = function (name: string):string {
return name
}
// 箭头函数
const getName = (name: string):string=>{
return name
}
- 可选参数/默认值
const getName = (name: string, age?: number):string | number => {
if(age) return age
return name
}
const getName = (name: string, age: number = 10):string => {
return name + age
}
3.任意参数
const getName = (...args: any[]):string => {
return args.join(',')
}
getName('detanx', 18)
泛型
- 创建时使用一个特殊字符代替声明的类型,在调用时声明数据的类型
function myfun<T>(args: T): T {
return args
}
myfun<string>('string')
- 可以在创建时指定默认的类型
function myfun<T=string>(args: T): T {
return args
}
泛型约束
- 传入的参数必须具备某一特新或属性等约定
interface IPerson {
name: string
age?: number
}
function myfun<T extends IPerson>(args: T): T {
return args
}
// 传入的参数必须有name,age可有可无
console.log("泛型约束",myfun<IPerson>({name:'string'}))
接口泛型
interface IPerson<T> {
name: string
age?: number
// hobbit?: string[] // 元素类型后面接上 []
hobbit?: Array<T> // 数组泛型
height?: number | string
weight?: number
[propName: string]: any; // 额外任意属性
}
let detanx: IPerson<string> = {
name: 'detanx',
age: 10,
hobbit: ['唱','跳','rap','篮球'],
sex: '男',
address: '成都'
}
索引类型
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
return names.map(n => o[n]);
}
// keyof T -> keyof Person = 'name' | 'age'
// T[K] -> person['name'] 具有类型 Person['name'] = string
interface Person {
name: string;
age: number;
}
let person: Person = {
name: 'Jarid',
age: 35
};
let strings: string[] = pluck(person, ['name']);
面向对象
修饰符
- TypeScript语言和Java还有C#很像(因为我只会这两个面向对象的语言),类中属性的访问可以用访问修饰符来进行限制。访问修饰符分为:public、protected、private。
- public:公有修饰符,可以在类内或者类外使用public修饰的属性或者行为,默认修饰符。
- protected:受保护的修饰符,可以本类和子类中使用protected修饰的属性和行为。
- private : 私有修饰符,只可以在类内使用private修饰的属性和行为。
class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }
}
new Animal("Cat").name; // 错误: 'name' 是私有的.
类
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
继承
- extends
class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }
public say() {
console.log('name',this.name)
}
}
class Rhino extends Animal {
constructor() { super("Rhino"); }
}
class Employee {
private name: string;
constructor(theName: string) { this.name = theName; }
}
let animal = new Animal("Goat");
let rhino = new Rhino();
let employee = new Employee("Bob");
rhino.say()
animal = rhino;
animal = employee; // 错误: Animal 与 Employee 不兼容.
- 类方法的重写
class Rhino extends Animal {
constructor() { super("Rhino"); }
public say(){
super.say()
console.log('Rhino name')
}
}
let rhino = new Rhino();
rhino.say()
命名空间
- 命名空间一个最明确的目的就是解决重名问题。
namespace beijing{
export class Detanx{
public name:string = 'detanx'
talk(){
console.log('我是北京detanx。')
}
}
}
namespace chengdu{
export class Detanx{
public name:string = 'detanx'
talk(){
console.log('我是成都detanx。')
}
}
}
let detanx1:beijing.Detanx = new beijing.Detanx()
let detanx2:chengdu.Detanx = new chengdu.Detanx()
detanx1.talk()