实例类型与类类型
在TypeScript中,类型系统是其核心特性之一,而实例类型与类类型是理解类型系统的重要概念。这两者之间的关系和区别对于编写类型安全的代码至关重要。
实例类型与类类型的定义
实例类型是指通过类实例化后对象的具体类型,而类类型则是指类本身的类型。在TypeScript中,类既是值也是类型,但它们的含义不同。
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
// 类类型
const PersonClass: typeof Person = Person;
// 实例类型
const personInstance: Person = new Person("Alice", 30);
类类型的使用场景
类类型通常用于需要操作类本身的场合,比如工厂函数或类装饰器。typeof
操作符可以获取类的类型。
function createInstance<T>(ctor: new (...args: any[]) => T, ...args: any[]): T {
return new ctor(...args);
}
const person = createInstance(Person, "Bob", 25);
实例类型的特性
实例类型包含了类的实例属性和方法,但不包括静态成员。TypeScript会自动为类声明生成一个同名的实例类型接口。
class Point {
static origin = { x: 0, y: 0 };
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
distance() {
return Math.sqrt(this.x ** 2 + this.y ** 2);
}
}
// 实例类型只包含实例成员
const p: Point = new Point(3, 4);
p.distance(); // 5
// p.origin; // 错误:实例类型不包含静态成员
类类型与构造签名
类类型通常表现为构造签名,描述如何通过new
操作符创建实例。这在泛型约束中特别有用。
interface AnimalConstructor {
new (name: string): Animal;
}
class Animal {
constructor(public name: string) {}
}
function createAnimal<T extends Animal>(ctor: new (name: string) => T, name: string): T {
return new ctor(name);
}
const cat = createAnimal(Animal, "Mittens");
类表达式与类型
类表达式也可以产生类型,这些类型的使用方式与类声明相同。
const Rectangle = class {
constructor(public width: number, public height: number) {}
area() {
return this.width * this.height;
}
};
type RectangleType = InstanceType<typeof Rectangle>;
const rect: RectangleType = new Rectangle(10, 20);
泛型类中的类型关系
泛型类会为每个具体类型参数生成不同的实例类型,但共享相同的类类型。
class Box<T> {
value: T;
constructor(value: T) {
this.value = value;
}
}
const numberBox: Box<number> = new Box(42);
const stringBox: Box<string> = new Box("hello");
// 类类型相同
const BoxClass: typeof Box = Box;
继承关系中的类型
子类的实例类型会包含父类的所有成员,而类类型的继承关系则更为复杂。
class Animal {
move() {
console.log("Moving");
}
}
class Dog extends Animal {
bark() {
console.log("Woof");
}
}
// 实例类型兼容性
const animal: Animal = new Dog(); // 合法
// animal.bark(); // 错误:Animal类型没有bark方法
// 类类型兼容性
const AnimalClass: typeof Animal = Animal;
// const DogClass: typeof Animal = Dog; // 合法
私有字段与类型
私有字段会影响类型的兼容性,即使两个类结构相同,如果私有字段来自不同的声明,它们的实例类型就不兼容。
class A {
private x = 1;
show() {
console.log(this.x);
}
}
class B {
private x = 1;
show() {
console.log(this.x);
}
}
const a: A = new A();
// const b: A = new B(); // 错误:A和B不兼容
抽象类的类型
抽象类既可以用作类类型,也可以产生实例类型,但抽象类本身不能被实例化。
abstract class Shape {
abstract area(): number;
display() {
console.log(`Area: ${this.area()}`);
}
}
// 类类型
const ShapeClass: typeof Shape = Shape;
// 实例类型
class Circle extends Shape {
constructor(public radius: number) {
super();
}
area() {
return Math.PI * this.radius ** 2;
}
}
const circle: Shape = new Circle(5);
接口与类类型
接口可以用来描述类类型的结构,包括静态成员和实例成员。
interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
}
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
class Clock implements ClockInterface {
currentTime: Date;
constructor(h: number, m: number) {
this.currentTime = new Date(2023, 0, 1, h, m);
}
setTime(d: Date) {
this.currentTime = d;
}
}
function createClock(ctor: ClockConstructor, h: number, m: number): ClockInterface {
return new ctor(h, m);
}
const clock = createClock(Clock, 12, 30);
类型查询与类
typeof
操作符在类上下文中有特殊行为,可以获取类的类型,包括静态成员。
class Logger {
static level = "INFO";
log(message: string) {
console.log(`[${Logger.level}] ${message}`);
}
}
type LoggerType = typeof Logger;
// 等价于
interface LoggerType {
new (): Logger;
level: string;
}
const loggerClass: LoggerType = Logger;
console.log(loggerClass.level); // "INFO"
构造函数参数类型
可以使用ConstructorParameters
工具类型来获取类构造函数的参数类型。
class User {
constructor(public id: number, public name: string) {}
}
type UserParams = ConstructorParameters<typeof User>;
// 等价于 [number, string]
function createUser(...args: UserParams): User {
return new User(...args);
}
const user = createUser(1, "Alice");
实例类型工具
TypeScript提供了InstanceType
工具类型来获取类的实例类型。
class Map<K, V> {
private data = new Map<K, V>();
set(key: K, value: V) {
this.data.set(key, value);
}
get(key: K): V | undefined {
return this.data.get(key);
}
}
type MapInstance<K, V> = InstanceType<typeof Map<K, V>>;
const stringMap: MapInstance<string, number> = new Map<string, number>();
stringMap.set("age", 30);
类与类型断言
在某些情况下,可能需要使用类型断言来处理类类型和实例类型之间的关系。
class Base {
baseMethod() {}
}
class Derived extends Base {
derivedMethod() {}
}
const base: Base = new Derived();
// (base as Derived).derivedMethod(); // 需要类型断言
// 类类型断言
const DerivedClass = Derived as typeof Base;
const derived = new DerivedClass();
装饰器中的类型
类装饰器接收的是类类型,可以修改或扩展类的行为。
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
类类型与映射类型
映射类型可以应用于类类型,生成新的类型。
class Product {
constructor(
public id: number,
public name: string,
public price: number
) {}
}
type PartialProduct = Partial<InstanceType<typeof Product>>;
const partialProduct: PartialProduct = { name: "Laptop" };
条件类型与类
条件类型可以根据类类型或实例类型进行类型判断。
type IsNumber<T> = T extends number ? true : false;
class Numeric {
value: number;
constructor(v: number) {
this.value = v;
}
}
type Test1 = IsNumber<InstanceType<typeof Numeric>>; // false
type Test2 = IsNumber<Numeric["value"]>; // true
类类型与索引访问
可以通过索引访问类型来获取类中的特定成员类型。
class Database {
connection: { host: string; port: number };
constructor(host: string, port: number) {
this.connection = { host, port };
}
}
type ConnectionType = Database["connection"];
// 等价于 { host: string; port: number }
类类型与函数重载
类方法可以像普通函数一样重载,这会影响实例类型。
class Overloaded {
greet(name: string): string;
greet(age: number): string;
greet(value: string | number): string {
if (typeof value === "string") {
return `Hello, ${value}`;
} else {
return `You are ${value} years old`;
}
}
}
const overloaded = new Overloaded();
overloaded.greet("Alice"); // OK
overloaded.greet(30); // OK
// overloaded.greet(true); // 错误
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn