TS 高级技巧学习记录

63 阅读1分钟

映射类型

type Readonly<T> = {
 readonly [P in keyof T]: T[P];
};

interface Point {
 x: number;
 y: number;
}

type ReadonlyPoint = Readonly<Point>;

条件类型

     type NonNullable<T> = T extends null | undefined ? never : T;

类装饰器

function LogClass(target: Function) {
 console.log(`Class ${target.name} was defined.`);
}

@LogClass
class MyClass {
 constructor() {}
}

方法装饰器

function LogMethod(target: any, key: string, descriptor: PropertyDescriptor) {
console.log(`Method ${key} was called.`);
}
class MyClass {
@LogMethod
myMethod() {
console.log("Inside myMethod.");
}
}
const instance = new MyClass();
instance.myMethod();

属性装饰器

function DefaultValue(value: any) {
 return (target: any, key: string) => {
 target[key] = value;
 };
}
class MyClass {
 @DefaultValue(42)
 myProperty: number;
}
const instance = new MyClass();
console.log(instance.myProperty); // Output: 42

参数装饰器

function LogParameter(target: any, key: string, parameterIndex: number) {
 console.log(`方法 ${key} 的参数 ${parameterIndex} 被调用了。`);
}
class MyClass {
 myMethod(@LogParameter value: number) {
 console.log(`在 myMethod 方法内,使用值 ${value}。`);
 }
}
const instance = new MyClass();
instance.myMethod(5);

命名空间

定义命名空间

namespace MyNamespace {
 export class MyClass {
   constructor(public value: number) {}
   displayValue() {
     console.log(`The value is: ${this.value}`);
   }
 }
}
// 使用完全限定的名称
const instance1 = new MyNamespace.MyClass(5);
instance1.displayValue(); // 输出:The value is: 5
// 使用命名空间导入
import MyClass = MyNamespace.MyClass;
const instance2 = new MyClass(10);
instance2.displayValue(); // 输出:The value is: 10

嵌套命名空间

namespace OuterNamespace {
 export namespace InnerNamespace {
   export class MyClass {
     constructor(public value: number) {}
     displayValue() {
       console.log(`The value is: ${this.value}`);
     }
   }
 }
}
// 使用完全限定的名称
const instance = new OuterNamespace.InnerNamespace.MyClass(15);
instance.displayValue(); // 输出:The value is: 15

混入

class TimestampMixin<TBase extends new (...args: any[]) => any>(Base: TBase) {

constructor(...args: any[]) {
super(...args);
}

getTimestamp() {
return new Date();
}
}
class MyBaseClass {
 constructor(public value: number) {}
 displayValue() {
 console.log(`The value is: ${this.value}`);
 }
}
class MyMixedClass extends TimestampMixin(MyBaseClass) {
 constructor(value: number) {
 super(value);
 }
}
const instance = new MyMixedClass(42);
instance.displayValue(); // 输出:The value is: 42
const timestamp = instance.getTimestamp();
console.log(`The timestamp is: ${timestamp}`); // 输出:The timestamp is: [当前日期和时间]

类型保护

function isString(value: any): value is string {
    return typeof value === "string";
}
function processValue(value: string | number) {
    if (isString(value)) {
        console.log(`The length of the string is: ${value.length}`);
    } else {
        console.log(`The square of the number is: ${value * value}`);
    }
}

processValue("hello"); // 输出: The length of the string is: 5
processValue(42); // 输出: The square of the number is: 1764

实用类型

interface Person {
    name: string;
    age: number;
    email: string;
}
type PartialPerson = Partial<Person>;
type ReadonlyPerson = Readonly<Person>;
type NameAndAge = Pick<Person, "name" | "age">;
type WithoutEmail = Omit<Person, "email">;

Partial

const partialPerson: PartialPerson = {
    name: "John Doe",
};

Readonly

const readonlyPerson: ReadonlyPerson = {
 name: "Jane Doe",
 age: 30,
 email: "jane@example.com",
};
// readonlyPerson.age = 31; // 错误:无法分配到 'age',因为它是只读属性

Pick

const nameAndAge: NameAndAge = {
 name: "John Smith",
 age: 25,
};
// nameAndAge.email; // 错误:在类型 'Pick<Person, "name" | "age">' 上不存在属性 'email'。

Omit

const withoutEmail: WithoutEmail = {
 name: "Jane Smith",
 age: 28,
};
// withoutEmail.email; // 错误:在类型 'Omit<Person, "email">' 上不存在属性 'email'。