阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 类的类型检查

类的类型检查

作者:陈川 阅读数:19253人阅读 分类: TypeScript

类型检查的基本概念

TypeScript 的类型检查系统是它的核心特性之一。类型检查发生在编译阶段,通过静态分析代码来确保类型的正确性。TypeScript 编译器会检查变量、函数参数、返回值等是否符合预期的类型。

let num: number = 42;
num = "hello"; // 错误:不能将类型"string"分配给类型"number"

原始类型检查

TypeScript 支持 JavaScript 的所有原始类型,并提供了额外的类型检查能力。

// 布尔值
let isDone: boolean = false;

// 数字
let decimal: number = 6;
let hex: number = 0xf00d;

// 字符串
let color: string = "blue";

// 数组
let list: number[] = [1, 2, 3];
let list2: Array<number> = [1, 2, 3]; // 泛型语法

// 元组
let x: [string, number];
x = ["hello", 10]; // OK
x = [10, "hello"]; // 错误

接口与类型检查

接口是 TypeScript 进行复杂类型检查的主要工具之一。

interface Person {
  name: string;
  age: number;
  address?: string; // 可选属性
  readonly id: number; // 只读属性
}

function greet(person: Person) {
  return `Hello, ${person.name}`;
}

const user = { name: "Alice", age: 30, id: 1 };
greet(user); // OK

const invalidUser = { name: "Bob" };
greet(invalidUser); // 错误:缺少必需的属性"age"和"id"

类与类型检查

TypeScript 对类的类型检查包括属性、方法和访问修饰符。

class Animal {
  private name: string;
  protected age: number;
  public readonly species: string;

  constructor(name: string, age: number, species: string) {
    this.name = name;
    this.age = age;
    this.species = species;
  }

  move(distance: number = 0) {
    console.log(`${this.name} moved ${distance}m.`);
  }
}

class Dog extends Animal {
  bark() {
    console.log("Woof! Woof!");
    // console.log(this.name); // 错误:name是私有的
    console.log(this.age); // OK: age是受保护的
  }
}

const dog = new Dog("Buddy", 5, "Canine");
dog.move(10);
dog.bark();
// dog.age = 6; // 错误:age是受保护的

泛型的类型检查

泛型提供了创建可重用组件的强大方式,同时保持类型安全。

function identity<T>(arg: T): T {
  return arg;
}

let output1 = identity<string>("myString"); // 显式指定类型
let output2 = identity(42); // 类型推断

class GenericNumber<T> {
  zeroValue: T;
  add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = (x, y) => x + y;

let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = (x, y) => x + y;

高级类型检查

TypeScript 提供了多种高级类型来满足复杂场景的需求。

// 联合类型
let padding: string | number;
padding = "1em"; // OK
padding = 10; // OK
padding = true; // 错误

// 类型别名
type StringOrNumber = string | number;
let value: StringOrNumber;
value = "hello"; // OK
value = 42; // OK

// 交叉类型
interface Named {
  name: string;
}
interface Aged {
  age: number;
}
type Person = Named & Aged;
let person: Person = { name: "Alice", age: 30 }; // OK
let invalidPerson: Person = { name: "Bob" }; // 错误:缺少age

// 类型断言
let someValue: any = "this is a string";
let strLength1: number = (<string>someValue).length; // 尖括号语法
let strLength2: number = (someValue as string).length; // as语法

类型守卫与类型推断

TypeScript 使用类型守卫来缩小类型范围,提高类型检查的精确度。

// 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 Bird {
  fly() {
    console.log("flying");
  }
}
class Fish {
  swim() {
    console.log("swimming");
  }
}
function move(pet: Bird | Fish) {
  if (pet instanceof Bird) {
    pet.fly();
  } else {
    pet.swim();
  }
}

// 自定义类型守卫
interface Cat {
  meow(): void;
}
function isCat(animal: any): animal is Cat {
  return (animal as Cat).meow !== undefined;
}
function handleAnimal(animal: Bird | Fish | Cat) {
  if (isCat(animal)) {
    animal.meow();
  } else if (animal instanceof Bird) {
    animal.fly();
  } else {
    animal.swim();
  }
}

映射类型与条件类型

TypeScript 的映射类型和条件类型提供了强大的类型转换能力。

// 映射类型
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};
type Partial<T> = {
  [P in keyof T]?: T[P];
};

interface Person {
  name: string;
  age: number;
}
type ReadonlyPerson = Readonly<Person>;
type PartialPerson = Partial<Person>;

// 条件类型
type TypeName<T> = T extends string
  ? "string"
  : T extends number
  ? "number"
  : T extends boolean
  ? "boolean"
  : T extends undefined
  ? "undefined"
  : T extends Function
  ? "function"
  : "object";

type T0 = TypeName<string>; // "string"
type T1 = TypeName<42>; // "number"
type T2 = TypeName<true>; // "boolean"

类型兼容性检查

TypeScript 的类型系统基于结构化类型,具有灵活性但也需要理解其规则。

interface Named {
  name: string;
}

class Person {
  constructor(public name: string) {}
}

let p: Named;
p = new Person("Alice"); // OK,因为结构兼容

let x = (a: number) => 0;
let y = (b: number, s: string) => 0;

y = x; // OK
x = y; // 错误:y需要两个参数,x只需要一个

enum Status {
  Ready,
  Waiting,
}
enum Color {
  Red,
  Blue,
  Green,
}
let status = Status.Ready;
status = Color.Red; // 错误:不同的枚举类型不兼容

声明合并与类型检查

TypeScript 允许声明合并,这会影响类型检查的行为。

interface Box {
  height: number;
  width: number;
}
interface Box {
  scale: number;
}
let box: Box = { height: 5, width: 6, scale: 10 }; // 合并后的接口

class Album {
  label: Album.AlbumLabel;
}
namespace Album {
  export class AlbumLabel {}
}

function buildLabel(name: string): string {
  return buildLabel.prefix + name + buildLabel.suffix;
}
namespace buildLabel {
  export let suffix = "";
  export let prefix = "Hello, ";
}
console.log(buildLabel("Sam Smith")); // "Hello, Sam Smith"

模块的类型检查

TypeScript 对模块系统有完整的类型检查支持。

// math.ts
export function square(x: number): number {
  return x * x;
}
export const PI = 3.14;

// app.ts
import { square, PI } from "./math";
console.log(square(4)); // 16
console.log(PI); // 3.14

// 类型导入
import type { SomeType } from "./some-module";
let value: SomeType;

// 动态导入
async function load() {
  const math = await import("./math");
  console.log(math.square(2));
}

装饰器的类型检查

装饰器是一种特殊类型的声明,可以附加到类声明、方法、访问符、属性或参数上。

function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

@sealed
class BugReport {
  type = "report";
  title: string;

  constructor(t: string) {
    this.title = t;
  }
}

function enumerable(value: boolean) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    descriptor.enumerable = value;
  };
}

class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }

  @enumerable(false)
  greet() {
    return "Hello, " + this.greeting;
  }
}

实用工具类型

TypeScript 提供了一系列内置的实用工具类型来帮助进行类型转换。

interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

// Partial: 所有属性变为可选
type PartialTodo = Partial<Todo>;

// Readonly: 所有属性变为只读
type ReadonlyTodo = Readonly<Todo>;

// Pick: 选择部分属性
type TodoPreview = Pick<Todo, "title" | "completed">;

// Omit: 忽略部分属性
type TodoInfo = Omit<Todo, "completed">;

// Record: 构造一个类型,其属性键为K,属性值为T
type Page = "home" | "about" | "contact";
type PageInfo = Record<Page, { title: string }>;

// Exclude: 从T中排除可以赋值给U的类型
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"

// Extract: 从T中提取可以赋值给U的类型
type T1 = Extract<"a" | "b" | "c", "a" | "f">; // "a"

// NonNullable: 从T中排除null和undefined
type T2 = NonNullable<string | number | undefined>; // string | number

// ReturnType: 获取函数返回值类型
type T3 = ReturnType<() => string>; // string

// InstanceType: 获取构造函数类型的实例类型
class C {
  x = 0;
  y = 0;
}
type T4 = InstanceType<typeof C>; // C

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌