TypeScript 是 JavaScript 的超集,添加了静态类型系统。它帮助你在开发阶段发现错误,提升代码质量和开发体验。
| 优势 | 说明 |
|---|---|
| 类型安全 | 编译时发现类型错误 |
| 智能提示 | IDE 更好的代码补全 |
| 代码文档 | 类型即文档 |
| 重构友好 | 安全地重构代码 |
| 团队协作 | 接口契约更清晰 |
# 安装 TypeScript
npm install -D typescript
# 初始化配置
npx tsc --init
# 编译文件
npx tsc
# 监听模式
npx tsc --watch
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
// 布尔值
let isDone: boolean = false
// 数字
let decimal: number = 6
let hex: number = 0xf00d
let binary: number = 0b1010
let octal: number = 0o744
// 字符串
let color: string = 'blue'
let name: string = `东巴文`
let sentence: string = `Hello, ${name}`
// 空值
function log(msg: string): void {
console.log(msg)
}
// null 和 undefined
let u: undefined = undefined
let n: null = null
// 大整数
let big: bigint = 100n
// Symbol
let sym: symbol = Symbol('key')
// 方式一:元素类型[]
let list: number[] = [1, 2, 3]
let names: string[] = ['东巴文', '用户A']
// 方式二:泛型数组
let list2: Array<number> = [1, 2, 3]
// 只读数组
let readonlyList: readonly number[] = [1, 2, 3]
let readonlyList2: ReadonlyArray<number> = [1, 2, 3]
// 多维数组
let matrix: number[][] = [[1, 2], [3, 4]]
// 固定长度和类型的数组
let tuple: [string, number] = ['东巴文', 18]
// 访问元素
console.log(tuple[0]) // 东巴文
console.log(tuple[1]) // 18
// 可选元素
let optionalTuple: [string, number?] = ['东巴文']
// 剩余元素
let restTuple: [number, ...string[]] = [1, 'a', 'b', 'c']
// 只读元组
let readonlyTuple: readonly [string, number] = ['东巴文', 18]
// 对象类型
let obj: object = { name: '东巴文' }
// 具体属性
let user: { name: string; age: number } = {
name: '东巴文',
age: 18
}
// 可选属性
let config: { host: string; port?: number } = {
host: 'localhost'
}
// 索引签名
let dict: { [key: string]: number } = {
a: 1,
b: 2
}
// any:任意类型,放弃类型检查
let anything: any = 'hello'
anything = 123
anything = { name: '东巴文' }
anything.doSomething() // 不报错,但可能运行时错误
// unknown:安全的 any
let uncertain: unknown = 'hello'
uncertain = 123
// 使用前需要类型检查
if (typeof uncertain === 'string') {
console.log(uncertain.toUpperCase())
}
// 类型断言
let value: unknown = '东巴文'
let length: number = (value as string).length
let length2: number = (<string>value).length
// void:没有返回值
function logMessage(msg: string): void {
console.log(msg)
}
// never:永不存在的值
function error(message: string): never {
throw new Error(message)
}
function infiniteLoop(): never {
while (true) {}
}
// 联合类型中的 never
type NonNullable<T> = T extends null | undefined ? never : T
interface User {
id: number
name: string
age?: number // 可选属性
readonly email: string // 只读属性
}
let user: User = {
id: 1,
name: '东巴文',
email: 'dongba@example.com'
}
user.name = '新名字'
// user.email = 'new@example.com' // 错误:只读属性
interface SearchFunc {
(source: string, subString: string): boolean
}
let search: SearchFunc = (src, sub) => {
return src.search(sub) !== -1
}
interface StringArray {
[index: number]: string
}
let arr: StringArray = ['东巴文', '用户A']
interface StringDictionary {
[key: string]: string | number
length: number
name: string
}
interface ClockInterface {
currentTime: Date
setTime(d: Date): void
}
class Clock implements ClockInterface {
currentTime: Date = new Date()
setTime(d: Date) {
this.currentTime = d
}
constructor(h: number, m: number) {}
}
interface Animal {
name: string
}
interface Dog extends Animal {
breed: string
}
interface Cat extends Animal {
meow(): void
}
// 多继承
interface Pet extends Dog, Cat {
owner: string
}
let pet: Pet = {
name: '小黄',
breed: '金毛',
owner: '东巴文',
meow() { console.log('喵') }
}
interface Box {
height: number
width: number
}
interface Box {
depth: number
}
let box: Box = {
height: 10,
width: 20,
depth: 30
}
type Name = string
type Age = number
type User = {
name: Name
age: Age
}
// 联合类型
type ID = string | number
type Status = 'pending' | 'approved' | 'rejected'
// 交叉类型
type Employee = User & {
employeeId: string
department: string
}
// 原始类型
type Point = [number, number]
type Callback = (data: unknown) => void
// interface:可扩展、可合并
interface User {
name: string
}
interface User {
age: number
}
// type:更灵活,支持联合、交叉、映射等
type ID = string | number
type PartialUser = Partial<User>
type ReadonlyUser = Readonly<User>
// 相同点:都可以描述对象
interface IUser {
name: string
}
type TUser = {
name: string
}
// 函数声明
function add(a: number, b: number): number {
return a + b
}
// 函数表达式
const subtract = (a: number, b: number): number => a - b
// 类型别名
type MathFunc = (a: number, b: number) => number
const multiply: MathFunc = (a, b) => a * b
const divide: MathFunc = (a, b) => a / b
// 可选参数
function greet(name: string, greeting?: string): string {
return greeting ? `${greeting}, ${name}` : `Hello, ${name}`
}
greet('东巴文') // Hello, 东巴文
greet('东巴文', 'Hi') // Hi, 东巴文
// 默认参数
function greetWithDefault(name: string, greeting: string = 'Hello'): string {
return `${greeting}, ${name}`
}
greetWithDefault('东巴文') // Hello, 东巴文
function sum(...numbers: number[]): number {
return numbers.reduce((total, n) => total + n, 0)
}
sum(1, 2, 3, 4, 5) // 15
// 重载签名
function format(input: string): string
function format(input: number): string
function format(input: string | number): string {
if (typeof input === 'string') {
return `String: ${input}`
}
return `Number: ${input}`
}
format('东巴文') // String: 东巴文
format(123) // Number: 123
// 泛型函数
function identity<T>(arg: T): T {
return arg
}
let output1 = identity<string>('东巴文')
let output2 = identity(123) // 类型推断
// 泛型接口
interface GenericIdentity<T> {
(arg: T): T
}
let myIdentity: GenericIdentity<number> = identity
// 泛型类
class GenericBox<T> {
private value: T
constructor(value: T) {
this.value = value
}
getValue(): T {
return this.value
}
}
let box = new GenericBox<string>('东巴文')
// 约束必须有 length 属性
interface Lengthwise {
length: number
}
function logLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg
}
logLength('hello') // 5
logLength([1, 2, 3]) // 3
// logLength(123) // 错误
// 多类型参数约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
const user = { name: '东巴文', age: 18 }
getProperty(user, 'name') // 东巴文
// getProperty(user, 'email') // 错误
// Partial:所有属性可选
type PartialUser = Partial<User>
// Required:所有属性必需
type RequiredUser = Required<User>
// Readonly:所有属性只读
type ReadonlyUser = Readonly<User>
// Pick:选取部分属性
type UserName = Pick<User, 'name'>
// Omit:排除部分属性
type UserWithoutId = Omit<User, 'id'>
// Record:构造对象类型
type UserMap = Record<string, User>
// ReturnType:获取函数返回类型
type R = ReturnType<() => string> // string
// Parameters:获取函数参数类型
type P = Parameters<(a: string, b: number) => void> // [string, number]
// NonNullable:排除 null 和 undefined
type NonNull = NonNullable<string | null | undefined> // string
// Extract:从联合类型中提取
type Extracted = Extract<'a' | 'b' | 'c', 'a' | 'b'> // 'a' | 'b'
// Exclude:从联合类型中排除
type Excluded = Exclude<'a' | 'b' | 'c', 'a' | 'b'> // 'c'
// 尖括号语法
let value: any = '东巴文'
let length: number = (<string>value).length
// as 语法(推荐)
let length2: number = (value as string).length
// 非空断言
let element = document.getElementById('app')!
element.innerHTML = '东巴文'
// 双重断言(不推荐)
let x = 'hello' as any as number
// typeof
function process(value: string | number) {
if (typeof value === 'string') {
return value.toUpperCase()
}
return value.toFixed(2)
}
// instanceof
class Dog {
bark() {}
}
class Cat {
meow() {}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark()
} else {
animal.meow()
}
}
// in 操作符
interface Bird {
fly(): void
}
interface Fish {
swim(): void
}
function move(animal: Bird | Fish) {
if ('fly' in animal) {
animal.fly()
} else {
animal.swim()
}
}
// 自定义类型守卫
function isFish(animal: Bird | Fish): animal is Fish {
return 'swim' in animal
}
function move2(animal: Bird | Fish) {
if (isFish(animal)) {
animal.swim()
} else {
animal.fly()
}
}
// 声明全局变量
declare const API_URL: string
declare function log(msg: string): void
// 声明模块
declare module 'my-library' {
export function doSomething(): void
export const version: string
}
// 声明文件(.d.ts)
// types/my-library/index.d.ts
declare module 'my-library' {
interface Options {
debug?: boolean
}
export function init(options?: Options): void
export const version: string
export default class MyLibrary {
constructor(options?: Options)
start(): void
stop(): void
}
}
掌握 TypeScript 基础后,你可以继续学习:
东巴文(db-w.cn)—— 让 TypeScript 更简单