TypeScript基础

类型声明

使用 :[type] 指定变量的类型

let a: number = 1 // 数字
let b: string = 'zhang' // 字符串
let c: boolean = true // 布尔
let d: object = {} // 对象
let e: array = [] // 数组
let f: null = null // Null
let g: undefined = undefined // Undefined
let h: void = function(){} // 空值
let i: any = [] // 表示任意类型,可以链式传播,不会对其进行类型检查
let j: unknown; // 表示不确定类型,只能赋值给unknown和any,会进行类型检测
let k: never; // 表示一个不可能出现的值,比如抛出错误,无限循环,并可以模拟只读属性
// 未声明类型的变量默认为any
let something === let something: any;

类型推论

如果没有指定类型,那么 TS 会按照类型推论推断出一个类型

let myFavoriteNumber = "seven";
myFavoriteNumber = 7; // error

联合类型

表示可以取多个类型的一种

let myFavoriteNumber: string | number;
myFavoriteNumber = "seven";
myFavoriteNumber = 7;
// 只能访问联合类型的共有属性(类型推断)
function getLength(something: string | number): number {
  return something.toString();
}

对象类型(interface)

我们使用接口(Interfaces)来定义对象的类型。

使用任意属性时,其他属性必须为任意属性的子集,可以使用联合类型

interface A {
  age: number; // 确定属性
  readonly name: boolean; // 只读属性
  male?: number; // 可选属性
  [propName: string]: string | number | boolean; // 任意属性
}
let obj: A = {
  name: true,
  age: 12,
  zjang: "123",
};

数组类型

let fibonacci: number[] = [1, 1, 2, 3, 5]; // 类型 + []
let fibonacci1: Array<number> = [1, 1, 2, 3, 5]; // 数组泛型
interface NumberArray {
  [index: number]: number;
}
let fibonacci2: NumberArray = [1, 1, 2, 3, 5]; // 接口(类数组)

函数类型

函数声明

function sum(x: number = 123, y?: number): number {
  // 校验输入和输出
  return x + y;
}
sum(1, 2);
// 可设置默认值
// 可选参数后不允许再出现必须参数

函数表达式

let sum: (x: number, y: number) => number = function (
  x: number,
  y: number
): number {
  return x + y;
};
sum(1, 2);
// TS中=>表示的是函数定义,左边输入类型,右边输出类型

接口定义

interface SearchFunc {
  (source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function (source: string, subString: string) {
  return source.search(subString) !== -1;
};

重载

重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
  if (typeof x === "number") {
    return Number(x.toString().split("").reverse().join(""));
  } else if (typeof x === "string") {
    return x.split("").reverse().join("");
  }
}
// TS会优先从最前面的函数定义开始匹配,所以要把精确匹配放在前面

类型断言

可以手动指定一个值的类型:值 as 类型

将联合类型断言为其中一个类型

interface Cat {
  name: string;
  run(): void;
}
interface Fish {
  name: string;
  swim(): void;
}
function isFish(animal: Cat | Fish) {
  if (typeof (animal as Fish).swim === "function") {
    return true;
  }
  return false;
}
// 需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误,比如执行了一个本不是它自己的方法。

将父类断言为更为具体的子类

interface ApiError extends Error {
  code: number;
}
interface HttpError extends Error {
  statusCode: number;
}
function isApiError(error: Error) {
  if (typeof (error as ApiError).code === "number") {
    return true;
  }
  return false;
}

将任何一个类型断言为 any

window.foo = 1; // error
(window as any).foo = 1; // √

将 any 断言为一个具体的类型

function getCacheData(key: string): any {
  return (window as any).cache[key];
}
interface Cat {
  name: string;
  run(): void;
}
const tom = getCacheData("tom") as Cat;
tom.run();
// getCacheData可能是是一个第三方库,不确定他的返回类型,当我们在使用时

断言的限制-兼容

interface A {
  name: string;
}
interface B {
  name: string;
  run(): void;
}
let tom: B = {
  name: "Tom",
  run: () => {
    console.log("run");
  },
};
let animal: A = tom; // √
// 若 A 兼容 B,那么 A 能够被断言为 B,B 也能被断言为 A
// 同理,若 B 兼容 A,那么 A 能够被断言为 B,B 也能被断言为 A

双重断言

interface Cat {
  run(): void;
}
interface Fish {
  swim(): void;
}
function testCat(cat: Cat) {
  return cat as any as Fish;
}
let cat = {
  run() {
    console.log(1);
  },
};
testCat(cat).swim();
// 这是非常危险的,可能导致运行时错误

类实现接口 implements

interface ClockInterface {
  currentTime: Date;
  setTime(d: Date);
}
class Clock implements ClockInterface {
  //
  currentTime: Date;
  setTime(d: Date) {
    this.currentTime = d;
  }
  constructor(h: number, m: number) {}
}

类修饰符 static、public、private、protected

class Person {
  protected name: string; // 行为类似private,但只可继承
  constructor(name: string) {
    this.name = name;
  }
}
class Zhang extends Person {
  constructor(name: string) {
    super(name);
  }
  static a = "a"; // 全局属性,创建全局变量
  public b = "b"; // 默认共有属性,内部外部都可访问
  private c = "c"; // 私有属性,外部不可访问
}
Zhang.a; // a
new Zhang("zhang").b; // b
new Zhang("zhang").c; // error!
new Zhang("zhang").name; // error!
new Person("zhang").name; // error!

抽象类 abstract

abstract class Person {
  private name: string; // 行为类似private,但只可继承
  constructor(name: string) {
    this.name = name;
  }
  call() {
    console.log("call");
  }
  abstract show(): void;
}
class Zhang extends Person {
  constructor(name: string) {
    super(name);
  }
  show() {
    console.log("show");
  }
  bind() {
    console.log("bind");
  }
}
let zhang: Person; // 允许创建一个抽象类型的引用
zhang = new Person("zhang"); // error! 不允许实例化抽象类
zhang = new Zhang("zhang"); // 可以实例化派生类
zhang.call();
zhang.show();
zhang.bind(); // error! 没有该方法

泛型

要求传入的类型和返回的类型一致

interface A {
  (arg: T): T;
}
let fun: A;
fun(1);
// 将泛型接口当做整体类型的一个接口
interface B<T> {
  (arg: T): T;
}
let fun: B<number>;
fun("string"); // error! 直观的看到类型
fun(123); // √
// 泛型约束
interface A {
  length: number;
}
function a<T extends A>(arg: T): T {
  console.log(arg.length);
  return arg;
}
a(123); // error! 参数arg必须符合接口A的规范
a([1, 2, 3]); // √
posted @ 2025-11-17 18:04  jinzhepro  阅读(6)  评论(0)    收藏  举报