前端识记
TypeScript 快速上手
typescript let s: string "hello" let n: number 42 let b: boolean true let arr: number[] [1, 2, 3] le…
最后更新 2026年9月12日
基础类型
let s: string = "hello"
let n: number = 42
let b: boolean = true
let arr: number[] = [1, 2, 3]
let tuple: [string, number] = ["age", 25]
let obj: { name: string; age?: number } = { name: "zx" } // ? 可选联合 / 交叉 / 字面量
type ID = string | number // 联合:A 或 B
type A = { x: number } & { y: number } // 交叉:A 且 B
type Dir = "up" | "down" // 字面量类型interface vs type
// interface:可声明合并,适合描述对象形状
interface User {
name: string
greet(): void
}
interface User { age: number } // 合并,不报错
// type:更灵活,能做联合/交叉/映射
type Result = Success | Failure
type Coord = [number, number]经验法则:描述对象/类的契约用 interface,其他都用 type。
泛型
function first<T>(arr: T[]): T | undefined {
return arr[0]
}
// 泛型约束
function getLen<T extends { length: number }>(x: T): number {
return x.length
}
// 常见内置泛型
type P = Partial<User> // 所有属性变可选
type R = Required<User> // 所有属性变必选
type K = Pick<User, "name"> // 只取部分属性
type O = Omit<User, "age"> // 排除部分属性
type Ret = ReturnType<typeof fn> // 函数返回类型
type Params = Parameters<typeof fn> // 函数参数类型类型收窄 (Narrowing)
function handle(x: string | number) {
if (typeof x === "string") {
x.toUpperCase() // 这里 x 是 string
}
}
// 自定义类型守卫
function isUser(v: unknown): v is User {
return typeof v === "object" && v !== null && "name" in v
}
// discriminated union(最常用的模式)
type Shape =
| { kind: "circle"; r: number }
| { kind: "rect"; w: number; h: number }
function area(s: Shape) {
switch (s.kind) {
case "circle": return Math.PI * s.r ** 2
case "rect": return s.w * s.h
}
}类型断言 / 非空断言
const el = document.getElementById("app") as HTMLDivElement
const el2 = document.getElementById("app")! // 非空断言,慎用枚举 vs const 对象
// 枚举(会生成运行时代码)
enum Status { Active, Inactive }
// 推荐:const 对象 + as const
const Status = { Active: 0, Inactive: 1 } as const
type Status = (typeof Status)[keyof typeof Status] // 0 | 1映射类型 & 条件类型
// 映射:批量变换属性
type Readonly<T> = { readonly [K in keyof T]: T[K] }
// 条件类型
type IsString<T> = T extends string ? true : false
// infer 提取
type Unwrap<T> = T extends Promise<infer U> ? U : T
// Unwrap<Promise<number>> => number常用 tsconfig 要点
{
"compilerOptions": {
"strict": true, // 永远开着
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler", // 现代打包器用这个
"noUncheckedIndexedAccess": true, // arr[i] 返回 T | undefined
"skipLibCheck": true
}
}面试题
1. any / unknown / never 的区别?
any:关闭类型检查,能赋值给任何类型,也能从任何类型赋值。逃生舱,尽量别用。unknown:安全的顶层类型。能接收任何值,但使用前必须收窄(typeof / 类型守卫)。never:底层类型,表示"不可能出现的值"。用于穷举检查和不会返回的函数。
2. interface 和 type 的核心区别?
interface支持声明合并(同名自动合并),type不行(会报错)。type能表达联合、交叉、条件、映射类型,interface不行。- 性能上
interface在大型项目中检查略快(编译器内部做了缓存)。
3. 解释 keyof 和 typeof
interface User { name: string; age: number }
type K = keyof User // "name" | "age"
const config = { port: 3000, host: "localhost" }
type Config = typeof config // { port: number; host: string }4. 什么是协变和逆变?
- 协变(covariant):子类型可以赋值给父类型。
Dog[]可赋值给Animal[]。 - 逆变(contravariant):函数参数位置反过来。
(a: Animal) => void可赋值给(d: Dog) => void。 - TS 默认函数参数是双变的(不安全),开启
strictFunctionTypes后变为逆变。
5. Partial<T> 怎么实现的?
type Partial<T> = { [K in keyof T]?: T[K] }追问:实现一个 DeepPartial?
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]
}6. as const 有什么用?
把值推断为最窄的字面量类型,并且所有属性变成 readonly。常用来替代 enum。
7. 怎么让 TS 在 switch 里检查穷举?
function assertNever(x: never): never {
throw new Error("Unexpected: " + x)
}
// switch 的 default 分支调用 assertNever(s)
// 如果漏了 case,s 不是 never,编译报错8. 泛型里 extends 的两种含义?
- 约束:
T extends HasLength→ T 必须满足 HasLength 的形状 - 条件类型:
T extends string ? A : B→ 如果 T 是 string 的子类型则 A,否则 B
9. 解释分布式条件类型
type ToArray<T> = T extends any ? T[] : never
type R = ToArray<string | number> // string[] | number[]
// 联合类型会被拆开逐个应用,而不是整体判断
// 要阻止分布:用 [T] extends [any]10. declare 关键字什么时候用?
声明一个"存在但不由这段代码提供"的东西——全局变量、.d.ts 文件里的类型、第三方库的 ambient module。不产生任何 JS 输出。
需要我把这些整理成一个 artifact 方便随时翻阅,还是直接存到 memory 里下次用?
反向链接(0)
还没有笔记链接到这里。在 Obsidian 里用 [[笔记名]] 引用它,这里就会出现,关系图谱上也会多出一条连线。