obsidian-computer
前端识记

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 里用 [[笔记名]] 引用它,这里就会出现,关系图谱上也会多出一条连线。

评论

关系图谱

工程化与性能优化网络React快速总结This指向TypeScript 快速上手Web components00-总览与阅读路线01-reactivity-effect与依赖收集02-reactivity-reactive-ref-computed03-runtime-挂载流程04-runtime-组件系统05-runtime-更新与diff06-compiler-三段式07-方法论-如何啃大型开源项目README前端小记01-js-core02-browser03-network04-css-html05-react06-vue07-engineering08-scenarios09-handwritten-js10-algorithms11-ai-frontend手写Promise踩坑记录前端识记AI总结mini-vue-reading前端面试

On this page