1、T[K] - 类型映射,获取类型的值
interface Person {
name: string
age: number
}
type V = Person[keyof Person]
// type V = "string" | "number"2、ts-toolbelt —TS 版lodash库
import type { Object } from 'ts-toolbelt'
// 使对象的部分属性变为可选
type T1 = Object.Optional<{ a: string;b: number }, 'a'>
// type T1 = {
// a?: string | undefined;
// b: number;
// }
// 合并两个对象,前面对象为undefined 的属性被后面对象对应属性覆盖
type T2 = Object.MergeUp<{ a: 'a1', b?:'b1' }, { a: 'a2', b: 'b2' }>
// type T2 = {
// a: "a1";
// b: "b1" | "b2";
// }3、假定对象的所有值都是数组类型, 如何获取对象值中的数组元素的类型
const data = {
a: ['x', 'y', 'z'],
b: [1, 2, 3]
} as const
type GetValueElementType<T extends { [key: string]: ReadonlyArray<any> }> = T[keyof T][number]
type TElement = GetValueElementType<typeof data>4、假定对象的值不都是数组类型,如何获取对象值中的数组元素的类型
实现1:通过extends判断对象的值类型,通过数组下标获取元素类型
type GetValueElementType<T> = { [K in keyof T]: T[K] extends ReadonlyArray<any> ? T[K][number] : never }[keyof T]实现2:通过extends判断对象的值类型,通过infer推断,获取数组元素类型
type GetValueElementType<T> = { [K in keyof T]: T[K] extends ReadonlyArray<infer E> ? E : never }[keyof T]5、实现一个函数getValue取得对象的value
可以使用keyof来增强getValue函数的类型功能:
function getValue<T extends Object, K extends keyof T>(o: T, key: K): T[K] {
return o[key];
}
const obj1 = { name: '张三', age: 18 };
const a = getValue(obj1, 'hh');6、in用于取联合类型的值,主要用于数组和对象的构造,切记不要用于interface
type name = 'firstName' | 'lastName';
type TName = {
[key in name]: string;
};7、获取参数this参数ThisParameterType
type ThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any ? U : unknown;8、剔除this参数OmitThisParameter
type OmitThisParameter<T> = unknown extends ThisParameterType<T>
? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T;9、找出T和U的差集和交集
type Diff<T, U> = T extends U ? never : T; // 找出T的差集
type Filter<T, U> = T extends U ? T : never; // 找出交集
type T30 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; // => "b" | "d"
type T31 = Filter<"a" | "b" | "c" | "d", "a" | "c" | "f">; // => "a" | "c"10、如何处理第三方库类型相关问题
【1】库本身没有自带类型定义,查找不到相关库类型,此时只需安装对应的类型库即可。
【2】库本身没有类型定义, 也没有相关的@type,此时需要自己声明一个declare module “lodash”。
【3】类型声明库有误,可以Import后通过extends或者merge能力对原类型进行扩展、// @ts-ignore忽略、忍受类型的丢失或不可靠性。
【4】类型声明报错,可以在compilerOptions的添加"skipLibCheck": true。
11、巧用类型收缩解决报错
类型断言:
function padLeft(value: string, padding: string | number) {
// 正常
return Array(padding as number + 1).join(" ") + value;
}但是如果有下面这种情况, 我们要写很多个as么?
function padLeft(value: string, padding: string | number) {
console.log((padding as number) + 3);
console.log((padding as number) + 2);
console.log((padding as number) + 5);
return Array((padding as number) + 1).join(' ') + value;
}类型守卫typeof in instanceof字面量类型保护:
【1】typeof: 用于判断number、string、boolean、symbol四种类型。
上面的例子适合使用typeof来进行类型守卫:
function padLeft(value: string, padding: string | number) {
if (typeof padding === 'number') {
console.log(padding + 3); //正常
console.log(padding + 2); //正常
console.log(padding + 5); //正常
return Array(padding + 1).join(' ') + value; //正常
}
if (typeof padding === 'string') {
return padding + value;
}
}【2】instanceof : 用于判断一个实例是否属于某个类。
class Man {
handsome = 'handsome';
}
class Woman {
beautiful = 'beautiful';
}
function Human(arg: Man | Woman) {
if (arg instanceof Man) {
console.log(arg.handsome);
console.log(arg.beautiful); // error
} else {
// 这一块中一定是 Woman
console.log(arg.beautiful);
}
}【3】in: 用于判断一个属性/方法是否属于某个对象。
interface B {
b: string;
}
interface A {
a: string;
}
function foo(x: A | B) {
if ('a' in x) {
return x.a;
}
return x.b;
}【4】字面量类型保护。
type Man = {
handsome: 'handsome';
type: 'man';
};
type Woman = {
beautiful: 'beautiful';
type: 'woman';
};
function Human(arg: Man | Woman) {
if (arg.type === 'man') {
console.log(arg.handsome);
console.log(arg.beautiful); // error
} else {
// 这一块中一定是 Woman
console.log(arg.beautiful);
}
}双重断言:
有时候使用as也会报错,因为as断言是有条件的,它只有当S类型是T类型的子集,或者T类型是S类型的子集时,S能被成功断言成T。
function handler(event: Event) {
const element = (event as any) as HTMLElement; // 正常
}12、巧用typescript支持的js最新特性优化代码
【1】可选链
let x=foo?.bar.baz();
// 等价于
var _a;
let x = (_a = foo) === null || _a === void 0 ? void 0 : _a.bar.baz();【2】空值联合
let x =foo ?? '22';
// 等价于
let x = (foo !== null && foo !== void 0 ? foo : '22');13、巧用高级类型灵活处理数据
Record类型工具可用于声明一些比较复杂的数据结构。
const AnimalMap = {
cat: { name: '猫', title: 'cat' },
dog: { name: '狗', title: 'dog' },
frog: { name: '蛙', title: 'wa' },
};
type AnimalType = 'cat' | 'dog' | 'frog';
interface AnimalDescription { name: string, title: string }
const AnimalMap: Record<AnimalType, AnimalDescription> = {
cat: { name: '猫', title: 'cat' },
dog: { name: '狗', title: 'dog' },
frog: { name: '蛙', title: 'wa' },
};14、对于敏感的数据, 可使用常量枚举的方式,在编译之后, 空空如也
const enum learn {
math,
language,
sports
}15、常量枚举不能包含计算成员
const enum Color {Red, Green, Blue = "blue".length};// error 不能包含计算成员16、外部枚举
使用declare enum定义的枚举类型,只会用于编译时的检查,编译结果中会被删除,外部枚举与声明语句一样,常出现在声明文件中,同时使用declare和const也是可以的。
17、类与接口implements
不同的类之间某一部分可能行为一致,那么为了不重复写两个一样的接口,可以使用implements实现重用interface,implements可以理解为"实现"。
interface Behavior {
eat(food: string): void
}
class Dog implements Behavior {
eat(foot) {}
}
class Cat implements Behavior {
eat(foot) {}
}
class habaDog extends Dog implements Behavior {
// 此时哈巴狗继承了狗类,就有了eat方法
}多个实现:
interface Behavior { // 行为接口
eat(food: string): void
}
interface Appearance { // 外表接口
fur:string
}
class Dog implements Behavior {
eat(foot) {}
}
class habaDog extends Dog implements Behavior, Appearance {
fur = ''
}18、接口继承
interface Fa {
surname: string
}
interface Son extends Fa {
name: string
}
const obj: Son = {
surname : 'z',
name: 'zc'
}19、接口继承class
class Fa {
constructor() {}
suck(){}
}
interface Son extends Fa {
suck():void;
name: string;
}