TypeScript是JavaScript的超集,也就是说TypeScript不只包含了JavaScript的所有内容,同时也包含其余内容。typescript
TypeScript = JavaScript + 类型系统 + ES6+新特性支持。
TypeScript原始类型能够和JavaScript基础类型一一对应。数组
const a: number = 1 // NaN const b: string = 'foo' const c: boolean = true // false const d: void = undefined const e: null = null const f: undefined = undefined const g: symbol = Symbol()
const arr1: Array<number> = [1, 2] const arr2: string[] = ['foo', 'bar']
指的是明确数量和类型的数组。函数
const arr: [number, string] = [1, 'foo'] // 能够经过如下方式正常获取数组中的元素 console.log(arr[1]) const [num, str] = arr
const obj: object = {} obj['name'] = 'zhangsan'
枚举类型指的是经过enum关键字定义一组键值对数据,数据定义完成后只能读取,不能修改。post
// 文章状态 enum PostStatus { // 草稿 Draft = 0, // 未发布 Unpublished = 1, // 已发布 Published = 2 } const post = { title: 'typescript', status: PostStatus.Published } // 直接经过enum声明的枚举类型能够用数字获取枚举名称 console.log(PostStatus[0]) // Draft
常量枚举:在enum关键字前面加上constthis
// 文章状态 const enum PostStatus { // 草稿 Draft = 0, // 未发布 Unpublished = 1, // 已发布 Published = 2 } // 此时再用数字获取枚举值就会报错 console.log(PostStatus[0])
never表示永远不存在值的类型,一般用于老是抛出异常或者永远不会有返回值的函数的返回值类型。rest
// 抛出异常 function fn(): never { throw new Error() } // 永远不会有返回值 function fn1(): never { while (true) { } }
// 能够在声明函数的时候用注解的方式为参数和返回值添加类型 function sum(a: number, b: number): number { return a + b } // 也能够用箭头函数表示函数类型 const sum1: (a: number, b: number) => number = function (a, b) { return a + b } // 函数声明后,调用时只能传入与声明相对应的参数类型和参数数量 // 或者使用可选参数和剩余参数 function test(a?: number, ...rest: number[]) { // todo }
在TypeScript中能够为同一个函数提供多个函数类型定义来进行函数重载。code
// 重载一 function test(x: number): number; // 重载二 function test(x: string): string; // 并非重载的一部分,只是实现逻辑 function test(x: any): any { if (typeof x === 'number') { return x } else if (typeof x === 'string') { return x } } test(1) test('foo')
ts中可使用any表示任意类型,提供any主要是为了兼容老的js代码。对象
let a: any = 1 // 能够改变a的类型 a = 'foo'
当未改变量指明类型的时候,ts能够经过参数值推断参数类型。继承
// 此时会自动推断a的类型为number const a = 1
ts中能够手动指定变量的类型。索引
const a: number | undefined = undefined // 将a的类型转为指定为number let b: number = a as number let c: number = <number>a
能够经过interface关键字设置对象必须知足某种要求。
const enum PostStatus { // 草稿 Draft = 0, // 未发布 Unpublished = 1, // 已发布 Published = 2 } // 要求文章必须具有title,status, id属性,能够有subtitle属性,其中id为只读属性 interface Post { title: string subtitle?: string status: PostStatus, readonly id: number } let obj: Post = { title: 'typescript', status: PostStatus.Draft, id: 1 } // 只读属性不能修改 obj.id = 2
针对cache这种属性不肯定的对象,可使用动态成员。
interface ICache { // 要求属性和属性值均为字符串 [key: string]: string } let cache: ICache = {} // 能够在使用的时候给对象添加符合要求的属性 cache['foo'] = 'bar'
TypeScript在ES2015的class类基础上添加了一些关键字,用于描述类的类型。
class Person { name: string // 私有属性,外部没法访, 能够添加readonly使其变为只读属性 private readonly type: string = 'person' // protected 受保护,只能在内部和子类内部使用 protected field: string = 'foo' constructor(name: string) { this.name = name } sayHi(msg: string) { // 能够在类内部访问私有属性 console.log(`my name is ${this.name}, i am a ${this.type}, ${msg}`) } } class Student extends Person { constructor(name: string) { super(name) } sayHi() { // 能访问父类受保护的属性,可是不能访问私有private属性 console.log(this.field) } }
当privite用在constructor前面时,那么这个类就不能在其余地方使用new生成实例。
class Book { title: string; private constructor(title: string) { this.title = title } // 可经过静态方法提供实例化对象的途径 static create(title: string) { return new Book(title) } } const ts = Book.create('TypeScript')
同时,类能够继承接口,表示类须要具有某些方法或者属性。
interface IBook { getContent(): string } // 类能够继承多个接口 class Book implements IBook { title: string; constructor(title: string) { this.title = title } // 必须实现接口 getContent(): string { return `TypeScript is a Language` } }
抽象类声明和普通类类似,只不过抽象类不能实例化,同时抽象类中的抽象方法须要子类实现。
abstract class Person { name: string; // 抽象属性 abstract field: string constructor(name: string) { this.name = name } // 抽象方法 abstract sayHi(msg: string): void } class Student extends Person { field: string = 'test'; sayHi(msg: string): void { console.log(msg) } }
泛型能够理解为将可变化的类型看成一个参数
const createNumberArray = function(length: number, value: number): number[] { return Array(length).fill(value) } const arr = createNumberArray(2, 1) // [1, 1] const createStringArray = function(length: number, value: string): string[] { return Array(length).fill(value) } const arr1 = createStringArray(2, 'foo') // [foo, foo]
在上面的例子中,createNumberArray和createStringArray除了参数和返回值的类型不一样以外,其他都同样,此时就可使用范型。
function createArray<T>(length: number, value: T): T[] { return Array(length).fill(value) } // 在使用时指定类型 const arr = createArray<number>(2, 1) // [1, 1] const arr1 = createArray<string>(2, 'foo') // [foo, foo]
interface Person { name: string } // 经过extends为类型添加约束,要求类型必须实现了Person接口 function intro<T extends Person>(person: T) { return person.name } intro({ name: 'zs' }) // ok intro(5) //error number类型没有实现Person
interface Person { name: string, age?: number } // 此范型要求T必须实现Person, U必须是T的属性中的某一个 // keyof是索引类型查询操做符,假设T是一个类型,那么keyof T产生的类型是T的属性名称字符串字面量类型构成的联合类型 function intro<T extends Person, U extends keyof T>(person: T, key: U) { return person[key] } intro({ name: 'zs' }, 'name') // 至关于 function intro<T extends Person, U extends 'name' | 'age'>(person: T, key: U) { return person[key] }
class Person { constructor() { } } function create<T>(c: { new(): T; }) { return new c() } const zs = create<Person>(Person)
import { camelCase } from 'lodash' // 当引用相似lodash这种没有类型声明文件的第三方库时,若是不明确声明引入的变量的类型,将会报错 declare let camelCase = (str?: string) => string console.log(camelCase('hello typescript'))
一般类型声明会放入*.d.ts文件中