ts类型定义的⾼阶⽤法:助⼒函数式编程(五)
给⼀个类型起个新名字:类型别名
类型别名会给⼀个类型起个新名字。 类型别名有时和接⼝很像,但是可以作⽤于原始值,联合类型,元组以及其它任何你需要⼿写的类型。
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {...}
类型别名不能被 extends和 implements
类型字⾯量
字符串字⾯量类型
字符串字⾯量类型允许你指定字符串必须的固定值。 在实际应⽤中,字符串字⾯量类型可以与联合类型,类型保护和类型别名很好的配合。 通过结合使⽤这些特性,你可以实现类似枚举类型的字符串。
使⽤固定的字⾯量字符串代替string作为更精确的类型定义
只能从三种允许的字符中选择其⼀来做为参数传递,传⼊其它值则会产⽣错误
type Easing = "ease-in" | "ease-out" | "ease-in-out";
可通过类型保护,实现⾯向字⾯量的类型断⾔
if (easing === "ease-in")
枚举字⾯量也可作为类型使⽤,
如我们在 ⼀节⾥提到的,当每个枚举成员都是⽤字⾯量初始化的时候枚举成员是具有类型的。
数字字⾯量也可作为类型使⽤。
函数式编程利器:可辨识联合
可辨识联合在函数式编程很有⽤处。 它具有3个要素:
1. 具有普通的单例类型属性— 可辨识的特征。 => 定义多个带有标志位的接⼝
2. ⼀个类型别名包含了那些类型的联合— 联合。 => 联合类型将多个接⼝变作⼀个接⼝
3. 此属性上的类型保护。 => 在类型保护下 根据标志位不同执⾏不同代码块
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
switch函数用法举例interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
在使⽤时添加类型保护,不同类型执⾏不同代码块。
function area(s: Shape) {
switch (s.kind) {
case "square": return s.size * s.size;
case "rectangle": return s.height * s.width;
case "circle": return Math.PI * s.radius ** 2;
}
}
上⾯的例⼦中,area的case中包含了参数类型Shape可能存在的所有类型,但是如果Shape中的类型增加了,area函数可能因没有符合类型的case⽽返回undefined,这是不好的,解决此问题我们可使⽤never类型。
never类型—即为除去所有可能情况后剩下的类型
function assertNever(x: never): never {
throw new Error("Unexpected object: " + x);
}
function area(s: Shape) {
switch (s.kind) {
case "square": return s.size * s.size;
case "rectangle": return s.height * s.width;
case "circle": return Math.PI * s.radius ** 2;
default: return assertNever(s); // error here if there are missing cases
}
}
此⽅法为没有对应的case时,将变量传⼊⼀个函数中,该函数参数类型定义为never,在此函数中对意料外的参数进⾏其他操作
链式开发原理:多态的this
⼀个类或对象中的⽅法返回this,以⽅便构成链式操作。
⾯试必问keyof:索引类型
通过 索引类型查询和 索引访问操作符来定义参数类型,⾯对⼀个函数中传⼊两个参数,参数A为参数B的部分索引,⽤来筛选处参数B的部分内容。
索引类型查询操作符:keyof T
对于任何类型 T, keyof T的结果为 T上已知的公共属性名的联合
索引访问操作符:T[K]
function pluck(o, names) {
return names.map(n => o[n]);
}
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
return names.map(n => o[n]);
}
interface Person {
name: string;
age: number;
}
let person: Person = {
name: 'Jarid',
age: 35
};
let strings: string[] = pluck(person, ['name']); // ok, string[]
interface Map<T> {
[key: string]: T;
}
let keys: keyof Map<number>; // string
let value: Map<number>['foo']; // number
## 类型直接的转换与继承:映射类型
在映射类型⾥,新类型以相同的形式去转换旧类型⾥每个属性。 例如,你可以令每个属性成为 readonly类型或可选的。
type Keys = 'option1' | 'option2';
type Flags = { [K in Keys]: boolean };
// ===
type Flags = {
option1: boolean;
option2: boolean;
}
type Readonly<T> = {
readonly [P in keyof T]: T[P];
}
type Partial<T> = {
[P in keyof T]?: T[P];
}
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
}
type Record<K extends string, T> = {
[P in K]: T;
}
type PersonPartial = Partial<Person>;
type ReadonlyPerson = Readonly<Person>;
type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
Readonly, Partial和 Pick是同态的,但 Record不是。 因为 Record并不需要输⼊类型来拷贝属性,所以它不属于同态,⾮同态类型本质上会创建新的属性,因此它们不会从它处拷贝属性修饰符。
Exclude<T, U> – 从T中剔除可以赋值给U的类型。
Extract<T, U> – 提取T中可以赋值给U的类型。
NonNullable<T> – 从T中剔除null和undefined。
ReturnType<T> – 获取函数返回值类型。
InstanceType<T> – 获取构造函数类型的实例类型。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。