TypeScript 进阶:接口、泛型与类型体操
上一期我们学习了 TypeScript 的基础类型。这一期,我们深入接口、泛型和高级类型系统——这些是 TypeScript 真正强大的地方。
接口(Interface)
接口定义了对象的形状。
基本用法
interface User {
id: number
name: string
email: string
}
function printUser(user: User) {
console.log(`${user.name} `)
}
printUser({
id: 1,
name: "Alice",
email: "alice@example.com"
})
可选属性
interface User {
id: number
name: string
email?: string // 可选
}
let user1: User = { id: 1, name: "Alice" }
let user2: User = { id: 2, name: "Bob", email: "bob@example.com" }
只读属性
interface User {
readonly id: number
name: string
}
let user: User = { id: 1, name: "Alice" }
user.id = 2 // Error: Cannot assign to 'id' because it is read-only
函数类型
interface SearchFunc {
(source: string, subString: string): boolean
}
let mySearch: SearchFunc = (source, sub) => {
return source.search(sub) !== -1
}
可索引类型
interface StringArray {
[index: number]: string
}
let myArray: StringArray = ["Bob", "Fred"]
let myStr: string = myArray[0]
类类型
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 Shape {
color: string
}
interface Square extends Shape {
sideLength: number
}
let square: Square = {
color: "blue",
sideLength: 10
}
多继承:
interface Shape {
color: string
}
interface PenStroke {
penWidth: number
}
interface Square extends Shape, PenStroke {
sideLength: number
}
泛型(Generics)
泛型让我们可以编写可重用的组件。
基本泛型
function identity(arg: T): T {
return arg
}
let output1 = identity("myString") // 类型为 string
let output2 = identity(123) // 类型推断为 number
泛型变量
function loggingIdentity(arg: T[]): T[] {
console.log(arg.length)
return arg
}
泛型类型
let myIdentity: (arg: T) => T = identity
// 对象字面量形式
let myIdentity2: { (arg: T): T } = identity
泛型接口
interface GenericIdentityFn {
(arg: T): T
}
function identity(arg: T): T {
return arg
}
let myIdentity: GenericIdentityFn = identity
把泛型参数移到接口:
interface GenericIdentityFn {
(arg: T): T
}
function identity(arg: T): T {
return arg
}
let myIdentity: GenericIdentityFn = identity
泛型类
class GenericNumber {
zeroValue: T
add: (x: T, y: T) => T
}
let myGenericNumber = new GenericNumber()
myGenericNumber.zeroValue = 0
myGenericNumber.add = (x, y) => x + y
泛型约束
interface Lengthwise {
length: number
}
function loggingIdentity(arg: T): T {
console.log(arg.length) // 现在可以访问 .length
return arg
}
loggingIdentity("hello") // OK
loggingIdentity([1, 2, 3]) // OK
loggingIdentity(123) // Error
在泛型中使用类类型
function create(c: { new(): T }): T {
return new c()
}
class BeeKeeper {
hasMask: boolean = true
}
class ZooKeeper {
nametag: string = "Mikle"
}
class Animal {
numLegs: number = 4
}
class Bee extends Animal {
keeper: BeeKeeper = new BeeKeeper()
}
class Lion extends Animal {
keeper: ZooKeeper = new ZooKeeper()
}
function createInstance<A>(c: new () => A): A {
return new c()
}
createInstance(Lion).keeper.nametag
createInstance(Bee).keeper.hasMask
高级类型
交叉类型
将多个类型合并为一个。
interface Person {
name: string
}
interface Loggable {
log(): void
}
type PersonLoggable = Person & Loggable
const person: PersonLoggable = {
name: "Alice",
log() {
console.log(this.name)
}
}
联合类型
type StringOrNumber = string | number
function add(a: StringOrNumber, b: StringOrNumber) {
if (typeof a === "string" || typeof b === "string") {
return a.toString() + b.toString()
}
return a + b
}
类型保护
interface Fish {
swim(): void
}
interface Bird {
fly(): void
}
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined
}
function move(pet: Fish | Bird) {
if (isFish(pet)) {
pet.swim()
} else {
pet.fly()
}
}
typeof 类型保护
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value
}
if (typeof padding === "string") {
return padding + value
}
throw new Error(`Expected string or number, got '${padding}'.`)
}
instanceof 类型保护
class Dog {
bark() {}
}
class Cat {
meow() {}
}
function speak(pet: Dog | Cat) {
if (pet instanceof Dog) {
pet.bark()
} else {
pet.meow()
}
}
null 检查
function f(str: string | null) {
if (str === null) {
return "default"
}
return str.toUpperCase()
}
可选链:
let x = foo?.bar.baz()
// 等价于
let x = foo === null || foo === undefined ? undefined : foo.bar.baz()
空值合并:
let x = foo ?? "default"
// 等价于
let x = foo !== null && foo !== undefined ? foo : "default"
类型推断
基础推断
let x = 3 // 推断为 number
let y = [0, 1, null] // 推断为 (number | null)[]
上下文推断
window.onmousedown = function(mouseEvent) {
console.log(mouseEvent.button) // 推断为 MouseEvent
}
类型推断方向
// 从右向左
let x = 3
// 从左向右(上下文类型)
window.onmousedown = function(mouseEvent) {
return mouseEvent.button
}
映射类型
从旧类型创建新类型。
Partial
所有属性变为可选。
type Partial = {
[P in keyof T]?: T[P]
}
interface User {
id: number
name: string
}
type PartialUser = Partial
// { id?: number; name?: string; }
Required
所有属性变为必选。
type Required = {
[P in keyof T]-?: T[P]
}
Readonly
所有属性变为只读。
type Readonly = {
readonly [P in keyof T]: T[P]
}
Pick
选取部分属性。
type Pick = {
[P in K]: T[P]
}
interface User {
id: number
name: string
email: string
}
type UserPreview = Pick
// { id: number; name: string; }
Omit
排除部分属性。
type Omit = Pick<T, Exclude>
type UserWithoutEmail = Omit
// { id: number; name: string; }
Record
创建对象类型。
type Record = {
[P in K]: T
}
type UserMap = Record
条件类型
根据条件选择类型。
type ReturnType = T extends (...args: any[]) => infer R ? R : any
function foo(): number {
return 1
}
type R = ReturnType // number
实战示例
API 响应类型
interface ApiResponse {
code: number
message: string
data: T
}
interface User {
id: number
name: string
}
async function fetchUser(id: number): Promise<ApiResponse> {
const response = await fetch(`/api/users/${id}`)
return response.json()
}
// 使用
const result = await fetchUser(1)
console.log(result.data.name)
事件处理
interface EventHandler {
(event: T): void
}
interface ClickEvent {
type: "click"
x: number
y: number
}
const handler: EventHandler = (event) => {
console.log(`Clicked at ${event.x}, ${event.y}`)
}
状态管理
type State = {
user: User | null
loading: boolean
error: string | null
}
type Action =
| { type: "FETCH_START" }
| { type: "FETCH_SUCCESS"; payload: User }
| { type: "FETCH_ERROR"; payload: string }
function reducer(state: State, action: Action): State {
switch (action.type) {
case "FETCH_START":
return { ...state, loading: true }
case "FETCH_SUCCESS":
return { ...state, loading: false, user: action.payload }
case "FETCH_ERROR":
return { ...state, loading: false, error: action.payload }
}
}
总结
TypeScript 的高级特性:
- 接口:定义对象形状
- 泛型:创建可重用组件
- 类型保护:缩小类型范围
- 映射类型:从旧类型创建新类型
- 条件类型:根据条件选择类型
下一期,我们学习 TypeScript 的项目配置和最佳实践。
进阶资源:
Views: 6
