怎样建立一个简单的网站,小说网站建设多少钱,wordpress改主题,九一人才网找工作条件类型 TypeScript 中的条件类型是一种高级类型#xff0c;它使我们根据不同的条件创建更复杂的类型。 TS中的条件类型就是在类型中添加条件分支#xff0c;以支持更加灵活的泛型 条件类型允许我们根据某个类型的属性是否满足某个条件#xff0c;来确定最终的类型。
type…条件类型 TypeScript 中的条件类型是一种高级类型它使我们根据不同的条件创建更复杂的类型。 TS中的条件类型就是在类型中添加条件分支以支持更加灵活的泛型 条件类型允许我们根据某个类型的属性是否满足某个条件来确定最终的类型。
type IsStringT T extends string ? yes : no;let result4: IsStringhello yes; // 类型为 no
let result3: IsString42 no; // 类型为 yes
console.log(result4, result3); // yes no
// let result2: IsStringhello no; // 类型为 no
// let result1: IsString42 yes; // 类型为 yes
// 通过给泛型参数传递不同的类型得到了不同的结果。infer 关键字 infer 关键字用于引入一种类型变量定义泛型里面推断出来的类型参数而不是外部传入的类型参数。 通常infer 关键字结合条件类型使用用于提取和推断类型信息。 // infer R 表示 R 类型是 TypeScript 自己推断出来的不用显式传入。
// 传入的 T 是函数, 就返回这个函数的结果类型。
type ExtractReturnTypeT T extends (...args: any[]) infer R ? R : never;function sum(a: string, b: string): string {return a b;
}
const result1: ExtractReturnTypetypeof sum hello; // 编译通过
console.log(result1) // hellotuple转union 元组转为联合类型
type ElementOfT T extends Arrayinfer P ? P : never;
type Tuple [string, number];
type TupleToUnion ElementOfTuple;
// 等同于
// type TupleToUnion string | numberlet arr: TupleToUnion 迪西
let arr2: TupleToUnion 9联合类型转成交叉类型 string | number 》string number
type T1 { name: string };
type T2 { age: number };
type ToIntersectionT T extends { a: (x: infer U) void, b: (x: infer U) void } ? U : never;
// 由于U需要同时满足T1的定义、T2的定义因此U需要包含T1、T2所有的类型因此T3就是T1 T2
type T3 ToIntersection{ a: (x: T1) void, b: (x: T2) void }; // type T3 T1 T2let obj: T3 {name: 迪西,age: 9,
}条件类型中的泛型推断 条件类型中的泛型推断是一个重要的概念// 条件类型中的泛型推断
type ExtractTypeT T extends infer U ? U : never;
// 使用泛型推断的条件类型
type ExtractedType ExtractTypestring[];
// 查看结果类型
let extractedValue: ExtractedType [1, 2];分布式条件类型 条件类型在处理联合类型时表现出一种分布式的行为type DiffT, U T extends U ? never : T; // 返回T 不属于U的子类型的部分
type FilterT, U T extends U ? T : never; // 返回T 属于U的子类型的部分type OnlyStrings Diffa | b | 1 | 2 | false, number | boolean; // a | b | false
type OnlyNumbers Filtera | b | 1 | 2 | true, number | boolean; // 1 | 2 | truelet str1: OnlyStrings a
let str2: OnlyNumbers 1内置条件类型 在 TypeScript 中有一些内置的条件类型比如 NonNullable它从类型中排除了 null 和 undefined。这里确保 value 的类型是非空的字符串。type NonNullableTypeT T extends null | undefined ? never : T;
const value1: NonNullableTypestring | null 迪西; // 编译通过
// const value2: NonNullableTypestring | null null; // 编译通过分配条件类型 分布式条件类型是指在联合类型上进行条件类型判断时该判断会分布到联合类型的每个成员上从而生成新的联合类型。type MyReturnTypeT T extends (...args: any[]) infer R ? R : any;
// MyReturnType 应用于函数类型和非函数类型。由于条件类型的分布式能力它会分别应用于函数类型和非函数类型的每个成员最终生成新的联合类型
function sum(a: number):number {return a;
}
// 编译通过 nonFuncResult 类型会被推断为string
const nonFuncResult: MyReturnTypestring Hello;
// 编译通过 funcResult 类型会被推断为number
const funcResult: MyReturnTypetypeof sum 3; 条件类型在映射类型中的应用 映射类型是一种用于从现有类型创建新类型的工具可以根据对象的属性是否满足条件来创建一个新类型从而对现有类型的属性进行转换、修改或过滤。type MakeNullableT {[K in keyof T]: T[K] extends number ? T[K] | null : T[K];
};// 使用映射类型中的条件类型
type User {id: number;name: string;age: number;
};type NullableUser MakeNullableUser;
// 将 T 中的 number 类型属性改为可空。通过应用于 User 类型我们得到了一个可空的 NullableUser 类型。
// 查看结果类型
let nullableUser: NullableUser {id: 1,name: John,age: null,
};条件类型中的嵌套应用 条件类型可以嵌套使用形成更复杂的类型判断。// 嵌套应用的条件类型
type FlattenArrayT T extends Arrayinfer U ? FlattenArrayU : T;// 使用嵌套应用的条件类型
type NestedArray [迪西, [小波, [拉拉, 嘻嘻], 哈哈]];type FlatArray FlattenArrayNestedArray;// 查看结果类型
let flatArray: FlatArray 迪西;函数 函数是JavaScript应用程序的基础。 它帮助你实现抽象层模拟类信息隐藏和模块。和JavaScript一样TypeScript函数可以创建有名字的函数和匿名函数。可以随意选择适合应用程序的方式不论是定义一系列API函数还是只使用一次的函数。 // Named function
function add(x, y) {return x y;
}
// 匿名函数 函数表达式是一种将函数赋值给变量的方式
let myAdd function(x, y) { return x y; };函数类型 函数类型包含2部分参数类型和返回值类型。 当写出完整函数类型的时候这两部分都是需要的
参数类型 为每个参数指定一个名字和类型。 这个名字只是为了增加可读性。 只要参数类型是匹配的那么就认为它是有效的函数类型而不在乎参数名是否正确。let myAdd: (baseValue: number, increment: number) number function(x: number, y: number): number { return x y; };返回值类型 返回值我们在函数和返回值类型之前使用( )符号使之清晰明了。 返回值类型是函数类型的必要部分如果函数没有返回任何值你也必须指定返回值类型为 void而不能留空。let myAdd function(x: number, y: number): number { return x y; };可选参数和默认参数 使用?符号来定义可选参数。可选参数可以不传递 在调用这些函数时我们可以选择传递或不传递可选参数。// 1).可选参数 ?代表参数可选age可传可不传
function func1(name: string, age?: number): void {console.log(name); // 张三
}
func1(张三);// 2).可选参数参数有默认值
function func2(url: string, method: string POST): void {console.log(url, method); // /list POST
}
func2(/list);剩余参数 可以使用…符号来定义剩余参数。剩余参数可以接受任意数量的参数并将它们作为数组传递给函数function func1(...arge: number[]): number {return arge.reduce((val, item) val item, 0);
}
console.log(func1(4, 5, 6, 7)); // 22函数重载 函数重载是一种在 TypeScript 中定义多个具有相同名称但参数类型和数量不同的函数的技术。这可以编写更清晰和类型安全的代码。
let obj: any {};
function func1(val: string): void;
function func1(val: number): void;
function func1(val: boolean): void;
function func1(val: any): void {if (typeof val string) {obj.name val;} else if (typeof val number) {obj.age val;} else if (typeof val boolean ) {obj.isSuccess val;}
}
func1(迪西);
func1(10);
func1(true);
console.log(obj); // {name: 迪西, age: 10, isSuccess: true}装饰器
要启用实验性的装饰器特性你必须在命令行或tsconfig.json里启用experimentalDecorators编译器选项
tsc --target ES5 --experimentalDecoratorstsconfig.json:
{compilerOptions: {target: ES5,experimentalDecorators: true}
}解决bug 编译ts文件报错Unable to resolve signature of method decorator when called as an expression. 官网的配置还是不能解决报错 可以通过监ts文件的热更新。 $ tsc 文件名 --target ES5 -w --experimentalDecorators 装饰器是一种特殊类型的声明它能够被附加到类声明方法 访问符属性或参数上。 装饰器使用 expression这种形式expression求值后必须为一个函数它会在运行时被调用被装饰的声明信息做为参数传入。 装饰器的作用 1只能在类中使用 2减少冗余代码量 3提高代码扩展性 装饰器的语法 装饰器本质上就是一个函数在特定的位置调用装饰器函数即可对数据进行扩展。// target 表示要扩展的数据可以是类、方法、属性、参数等。
function myDecorator(target: any) {// 对 target 进行处理
}类装饰器 类装饰器在类声明之前被声明紧靠着类声明。 类装饰器应用于类构造函数可以用来监视修改或替换类定义。 类装饰器不能用在声明文件中( .d.ts)也不能用在任何外部上下文中 类装饰器表达式会在运行时当作函数被调用类的构造函数作为其唯一的参数。 如果类装饰器返回一个值它会使用提供的构造函数来替换类的声明。 注意 如果你要返回一个新的构造函数你必须注意处理好原来的原型链。 在运行时的装饰器调用逻辑中 不会为你做这些。 function classDecoratorT extends {new(...args:any[]):{}}(constructor:T) {return class extends constructor {newProperty new property;hello override;}
}classDecorator
class Greeter {property property;hello: string;constructor(m: string) {console.log(m) // worldthis.hello m;}
}console.log(new Greeter(world)); // class_1 {property: property, hello: override, newProperty: new property}装饰器工厂 若需要要定制一个修饰器如何应用到一个声明上得写一个装饰器工厂函数。 装饰器工厂就是一个简单的函数它返回一个表达式以供装饰器在运行时调用。function color(value: string) { // 这是一个装饰器工厂return function (target) { // 这是装饰器// do something with target and value...}
}function addNameEatFactory(name: string):Function {return function addNameEat(constructor: Function):void {constructor.prototype.name name;constructor.prototype.eat (m) {console.log(m) // 2};};
};
addNameEatFactory(Jerry)
class Person {name: string;eat: Function | undefined;constructor(n) {console.log(n) // 1this.name n;}
}
let p: Person new Person(1);
console.log(p.name); // 1
p.eat(2);属性、方法装饰器 方法装饰器声明在一个方法的声明之前紧靠着方法声明。 它会被应用到方法的 属性描述符上可以用来监视修改或者替换方法定义。 方法装饰器不能用在声明文件( .d.ts)重载或者任何外部上下文比如declare的类中。 方法装饰器表达式会在运行时当作函数被调用传入下列3个参数 1对于静态成员来说是类的构造函数对于实例成员是类的原型对象。 2成员的名字。 3成员的属性描述符。 注意 如果代码输出目标版本小于ES5属性描述符将会是undefined。 如果方法装饰器返回一个值它会被用作方法的属性描述符。 注意 如果代码输出目标版本小于ES5返回值会被忽略。 function upperCase(target: any, propertyKey: string) {// console.log(target, propertyKey); // { getName: [Function (anonymous)], sun: [Function (anonymous)] } namelet value target[propertyKey]const getter () value;const setter (newVal: string) { value newVal.toUpperCase(); };if (delete target[propertyKey]) {Object.defineProperty(target, propertyKey, {get: getter,set: setter,enumerable: true,configurable: true});}
}
// 如果装饰的是静态属性target就是构造函数
function staticPrototypeDecorator(target: any, propertyKey: string) {// console.log(target, propertyKey); // [Function: Person] { age: 18 } age
}
function noEnumerable(target: any, propertyKey: string, descriptor: PropertyDescriptor) {descriptor.enumerable false; // 不可枚举
}
function toNumber(target: any, propertyKey, descriptor: PropertyDescriptor) {let oldMethod descriptor.value;descriptor.value function (...args: any[]) {console.log(args) // [1, 2, 3, 4]args args.map(item parseFloat(item));return oldMethod.apply(this, args)}
}
class Person {upperCasename: string jerry; // 实例属性staticPrototypeDecoratorstatic age: number 18; // 静态属性noEnumerablegetName() { console.log(this.name); }; // 实例方法toNumbersum(...args: any[]) { // 实例方法console.log(args) // [1, 2, 3, 4]return args.reduce((prev: number, next: number) prev next, 0);}
}
let p new Person();
console.log(p.name); // JERRY
console.log(p.sum(1, 2, 3, 4)); // 10参数装饰器 参数装饰器声明在一个参数声明之前紧靠着参数声明。 参数装饰器应用于类构造函数或方法声明。 参数装饰器不能用在声明文件.d.ts重载或其它外部上下文里。 参数装饰器表达式会在运行时当作函数被调用传入下列3个参数 1对于静态成员来说是类的构造函数对于实例成员是类的原型对象。 2成员的名字。 3参数在函数参数列表中的索引。 注意 参数装饰器只能用来监视一个方法的参数是否被传入。 // target静态属性指构造函数实例属性、实例方法值构造函数的原型// methodName方法的名称// paramIndex参数的索引function addAge(target: any, methodName: string, paramIndex: number) {// console.log(target, methodName, paramIndex); // { login: [Function (anonymous)] } login 1target.age1 18;}class Person {age1: number;login(username: string, addAge password: string) {console.log(this.age1, username, password); // 18 admin admin123}}let p new Person();p.login(admin, admin123); // 18 admin admin123装饰器执行顺序 1class装饰器最后执行后写的类装饰器先执行2方法和参数中的装饰器参数装饰器先执行再执行方法装饰器3方法和属性装饰器谁在前面先执行谁4先内后外 先上后下执行 function ClassDecorator1() {return function (target) {console.log(ClassDecorator1);}
}
function ClassDecorator2() {return function (target) {console.log(ClassDecorator2);}
}
function PropertyDecorator(name: string) {return function (target, propertyName) {console.log(PropertyDecorator, propertyName, name);}
}
function MethodDecorator() {return function (target, propertyName) {console.log(MethodDecorator, propertyName);}
}
function ParameterDecorator() {return function (target, propertyName, index) {console.log(ParameterDecorator, propertyName, index);}
}
ClassDecorator1()
ClassDecorator2()
class Person {PropertyDecorator(name)name: string ;PropertyDecorator(age)age: number 9;MethodDecorator()hello(ParameterDecorator() hello: string, ParameterDecorator() word: string) {}
}