概述
- JavaScript的超集
- 解决JavaScript类型系统的问题
- 前端领域的第二语言
- 任何一种JavaScript运行环境都支持(浏览器、Node等)
- 功能强大、生态健全
- 属于渐进式
快速上手
yarn init --yes // 生成package.json管理依赖项
yarn add typescript --dev // node_modules/.bin 有tsc命令(编译ts代码)
yarn tsc test.ts // 生成同名的JS文件 test.js
yarn tsc --init // 生成tsconfig.json文件 直接运行yarn tsc 才走该配置文件
// tsconfig.json常用简单配置:
{
"compilerOptions": {
"target" : "es5",
"module": "commonjs", "lib": ["ES2015", "DOM", "ES2017"], "sourceMap": true, /* Generates corresponding '.map' file. */ "outDir": "dist", "rootDir: "src",
"strict": true /* Enable all strict type-checking options. */
}
}
原始数据类型
- string
- number
- boolean
- null
- undefined
- void
- symbol
// 原始数据类型
const a: string = 'foobar'
const b: number = 100 // NaN Infinity
const c: boolean = true // false
// 在非严格模式(strictNullChecks)下,
// string, number, boolean 都可以为空
// const d: string = null
// const d: number = null
// const d: boolean = null
const e: void = undefined
const f: null = null
const g: undefined = undefined
// Symbol 是 ES2015 标准中定义的成员,
// 使用它的前提是必须确保有对应的 ES2015 标准库引用
// 也就是 tsconfig.json 中的 lib 选项必须包含 ES2015
const h: symbol = Symbol()
// Promise
// const error: string = 100
数组类型
// 数组类型的两种表示方式
const arr1: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]
// 案例 -----------------------
// 如果是 JS,需要判断是不是每个成员都是数字
// 使用 TS,类型有保障,不用添加类型判断
function sum (...args: number[]) {
return args.reduce((prev, current) => prev + current, 0)
}
sum(1, 2, 3) // => 6
元组类型
明确元素的数量、类型的数组
一般用于函数的多个返回值
const tuple: [number, string] = [18, 'zce']
// const age = tuple[0]
// const name = tuple[1]
const [age, name] = tuple
// ---------------------
const entries: [string, number][] = Object.entries({
foo: 123,
bar: 456
})
const [key, value] = entries[0]
// key => foo, value => 123
枚举类型
// 用对象模拟枚举
// const PostStatus = {
// Draft: 0,
// Unpublished: 1,
// Published: 2
// }
// 标准的数字枚举
// enum PostStatus {
// Draft = 0,
// Unpublished = 1,
// Published = 2
// }
// 数字枚举,枚举值自动基于前一个值自增
// enum PostStatus {
// Draft = 6,
// Unpublished, // => 7
// Published // => 8
// }
// 字符串枚举
// enum PostStatus {
// Draft = 'aaa',
// Unpublished = 'bbb',
// Published = 'ccc'
// }
// 常量枚举,不会侵入编译结果
const enum PostStatus {
Draft,
Unpublished,
Published
}
const post = {
title: 'Hello TypeScript',
content: 'TypeScript is a typed superset of JavaScript.',
status: PostStatus.Draft // 3 // 1 // 0
}
// PostStatus[0] // => Draft
函数类型
对输入输出进行类型限制
// -------------------函数声明-------------------
// 参数可选表现为 ?符号或者添加默认值
function func1 (a: number, b: number = 10, ...rest: number[]): string {
return 'func1'
}
func1(100, 200)
func1(100)
func1(100, 200, 300)
// -------------------函数表达式----------------------
const func2: (a: number, b: number) => string = function (a: number, b: number): string {
return 'func2'
}
任意类型
不存在类型检查
function stringify (value: any) {
return JSON.stringify(value)
}
stringify('string')
stringify(100)
stringify(true)
let foo: any = 'string'
foo = 100
foo.bar()
// any 类型是不安全的
隐式类型推断
let age = 18 // number
// age = 'string'
// 如果typescript无法推断一个变量的类型,则将这个变量的类型标记为any
let foo
foo = 100
foo = 'string'
// 建议为每个变量添加明确的类型标注
类型断言
// 假定这个 nums 来自一个明确的接口
const nums = [110, 120, 119, 112]
const res = nums.find(i => i > 0) // typescript推断res类型为number或undefined
// const square = res * res
const num1 = res as number
const num2 = <number>res // JSX 下不能使用
接口
约定对象中有哪些成员以及成员的类型,约束对象的结构
// -----------------接口基础-----------------
interface Post {
title: string
content: string
}
function printPost (post: Post) {
console.log(post.title)
console.log(post.content)
}
printPost({
title: 'Hello TypeScript',
content: 'A javascript superset'
})
// -----------------接口补充-----------------
// 可选成员、只读成员
interface Post {
title: string
content: string
subtitle?: string
readonly summary: string
}
const hello: Post = {
title: 'Hello TypeScript',
content: 'A javascript superset',
summary: 'A javascript'
}
// hello.summary = 'other'
// 动态成员
interface Cache {
[prop: string]: string
}
const cache: Cache = {}
cache.foo = 'value1'
cache.bar = 'value2'
类
用来描述一类具体对象的抽象成员,Typescript增强了class的相关语法。
基本使用
class Person {
name: string // = 'init name'
age: number
constructor (name: string, age: number) {
this.name = name
this.age = age
}
sayHi (msg: string): void {
console.log(`I am ${this.name}, ${msg}`)
}
}
类的访问修饰符
- private (类内访问)
- public(默认)
- protected(类内、子类访问)
class Person {
public name: string // = 'init name'
private age: number
protected gender: boolean
constructor (name: string, age: number) {
this.name = name
this.age = age
this.gender = true
}
sayHi (msg: string): void {
console.log(`I am ${this.name}, ${msg}`)
console.log(this.age)
}
}
class Student extends Person {
// constructor默认是public,若设为private,则不可在外实例化,也不可被继承
private constructor (name: string, age: number) {
super(name, age)
console.log(this.gender)
}
// 可通过静态方法创建实例
static create (name: string, age: number) {
return new Student(name, age)
}
}
const tom = new Person('tom', 18)
console.log(tom.name)
// console.log(tom.age)
// console.log(tom.gender)
const jack = Student.create('jack', 18)
类的只读属性
在声明或构造时初始化
class Person {
public name: string // = 'init name'
private age: number
// 只读成员
protected readonly gender: boolean
constructor (name: string, age: number) {
this.name = name
this.age = age
this.gender = true
}
sayHi (msg: string): void {
console.log(`I am ${this.name}, ${msg}`)
console.log(this.age)
}
}
const tom = new Person('tom', 18)
console.log(tom.name)
// tom.gender = false
类与接口
interface Eat {
eat (food: string): void
}
interface Run {
run (distance: number): void
}
class Person implements Eat, Run {
eat (food: string): void {
console.log(`优雅的进餐: ${food}`)
}
run (distance: number) {
console.log(`直立行走: ${distance}`)
}
}
class Animal implements Eat, Run {
eat (food: string): void {
console.log(`呼噜呼噜的吃: ${food}`)
}
run (distance: number) {
console.log(`爬行: ${distance}`)
}
}
抽象类
只能被继承,不能被实例化,可以包含一些实现
子类必须实现父类的抽象方法
abstract class Animal {
eat (food: string): void {
console.log(`呼噜呼噜的吃: ${food}`)
}
abstract run (distance: number): void
}
class Dog extends Animal {
run(distance: number): void {
console.log('四脚爬行', distance)
}
}
const d = new Dog()
d.eat('嗯西马')
d.run(100)
泛型
定义时不指定类型,使用时再指定。
定义时不能明确的类型变成一个参数,使用时才去传递。
function createNumberArray (length: number, value: number): number[] {
const arr = Array<number>(length).fill(value)
return arr
}
function createStringArray (length: number, value: string): string[] {
const arr = Array<string>(length).fill(value)
return arr
}
function createArray<T> (length: number, value: T): T[] {
const arr = Array<T>(length).fill(value)
return arr
}
// const res = createNumberArray(3, 100)
// res => [100, 100, 100]
const res = createArray<string>(3, 'foo')
类型声明
如果第三方模块不存在类型声明,可用 yarn add @types/模块名 安装,也可手动 declare
import { camelCase } from 'lodash'
// declare function camelCase (input: string): string
const res = camelCase('hello typed')