typescript
作为前端使用最多的框架之一,快来看看下面这些隐藏的高级技巧吧
Mapped Types
当我们在声明类型的时候,可以借助 mapped types">Mapped Types
的方式对基础类进行扩展,这样就可以减少定义重复的基础类型
type Ev = {
add: string;
remove: string;
move: string;
}
type OnEvents = {
[k in keyof Ev as `on${Capitalize<Exclude<k, 'move'>>}`]: () => void
}
const userActions: OnEvents = {
onAdd: () => { },
onRemove: () => { },
}
上面的类型声明利用了 keyof
对原始的 基础类型 Ev
进行遍历形成行的 OnEvents
类型,这个类型的 key
的成员就是 Ev
类型中的 基础类型,同时这里使用了 as
对 重新的 map
的类型进行新的定义
as `on${Capitalize<Exclude<k, 'move'>>}`
我们可以将 key
的声明单独拎出来看,上面使用了 Exclude
将 move
字段排除,并且通过 Capitalize
工具类将剩余的 key
转换成 onAdd
和 onRemove
Template literals
Template literals 模板字面类型通过 模板字符串语法,借以字符串字面类型为基础,并能通过联合扩展到许多字符串
type GapType = "margin" | "padding"
type GapDirection = "top" | "right" | "bottom" | "left"
type GapCss = `${GapType}-${GapDirection}`
type SizeType = 'rem' | 'px' | '%';
type SizeCss = `${number}${SizeType}`
type MarginPadding = {
[Key in GapCss]?: SizeCss
}
const margin: MarginPadding = {
'margin-left': '1rem'
}
Never type
Never Type">Never Type
类型表示的是那些永不存在的值的类型。它是任何类型的子类型,但没有类型是 never
的子类型(除了 never
本身)。never
类型常用于表示不可能发生的事情,例如一个函数永远不会正常返回,或者一个变量将永远不会有值.
type NoEmptyString<T> = T extends '' ? never : T;
function failOnEmptyString<T extends string>(input: NoEmptyString<T>) {
if (!input.length) {
throw new Error('input is empty');
}
}
failOnEmptyString('');
所以上面的案例通过 never
类型进行限定,表示 failOnEmptyString
函数永远不能输入空的字符串
satisfies 操作符
satisfies 在 Typescript 4.9+ 版本才支持
TypeScript 中的 satisfies">satisfies
操作符用于断言特定对象满足特定类型。这与使用类型断言(如 as
)不同,因为 satisfies
不会改变变量的类型;它只是检查变量是否与指定类型兼容。如果类型检查失败,代码将无法编译,因此它是一种编译时特性。
type Colors = "red" | "green" | "blue";
type RGB = [red: number, green: number, blue: number];
const palette: Record<Colors, string | RGB> = {
red: [255, 0, 0],
green: "#00ff00",
blue: [0, 0, 255]
};
const red = palette.red.find(v => v === 255)
相信上面的报错在日常开发中,经常会遇到的,平常的解决方法大多数都是 使用 as
大法, 但是有时候 as
大法也不是很好用。 用 satisfies
就可以很好解决这种情况
const palette = {
red: [255, 0, 0],
green: "#00ff00",
blue: [0, 0, 255]
} satisfies Record<Colors, string | RGB>;
infer
在 TypeScript 中,"infer
"关键字是一个强大的功能,可用于Conditional Types
条件类型的上下文中,根据使用它们的上下文自动推断类型。这可以使类型实用程序更加灵活,能够处理复杂的类型场景,而无需用户进行显式类型声明。
type ReturnType<T> = T extends (...args: any[]) => infer P ? P : any;
infer 关键字必须使用在「条件类型的子句」,也就是extends
后面?
前面的位置
infer
的一些使用场景
- 推断对象的值类型
type ObjVal<T> = T extends { x: infer U; } ? U : never;
const a: ObjVal<{ x: string }> = '2323'
推断函数的参数类型
type FuncParamType<T> = T extends (x: infer U) => any ? U : never; let aa: FuncParamType<(age: number) => false> = 2432 let aa1: FuncParamType<(age: number) => false> = '2432'
推断 Generice 参数的类型
type PromiseType<T> = T extends Promise<infer U> ? U : never; let b: PromiseType<Promise<boolean>> = false let bb: PromiseType<boolean> = false
推断
String
的一部分type RemoveUnderscore<T> = T extends `_${infer R}` ? R : T; let cc: RemoveUnderscore<number> = 2323 let cc1: RemoveUnderscore<string> = `_I have underscore`
只有以
_
开头的字符串才会被推断成R
类型
Type Guard 类型守卫
在 TypeScript
中,类型守卫(Type Guards
)是一种技术或模式,它使你能够在编译时期确定一个变量的类型。这种机制对于在运行时根据不同的类型执行不同的操作非常有用,尤其是在处理联合类型或更复杂的类型结构时。
在 TS 中,我们可以使用 typeof
、instanceOf
、is
等操作符来定义类型守卫
typeof
function padLeft(value: string | string[], padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
console.log(padLeft("Hello, world", 4));
console.log(padLeft("Hello, world", "John says "));
instanceOf
class Bird {
fly() {}
}
class Fish {
swim() {}
}
function move(pet: Bird | Fish) {
if (pet instanceof Bird) {
pet.fly();
} else if (pet instanceof Fish) {
pet.swim();
}
}
const myBird = new Bird();
const myFish = new Fish();
move(myBird);
move(myFish);
is
利用类型谓词 parameter is Type
来确定变量的类型
interface Bird {
fly(): void;
layEggs(): void;
}
interface Fish {
swim(): void;
layEggs(): void;
}
function isFish(pet: Bird | Fish): pet is Fish {
return (pet as Fish).swim !== undefined;
}
function getPetAction(pet: Bird | Fish) {
if (isFish(pet)) {
pet.swim();
} else {
pet.fly();
}
}
const pet = getPetAction({ fly: () => console.log("fly"), layEggs: () => console.log("egg") });
由于篇幅有限,关注小编,获取后续更多关于 typescript
使用技巧
如果觉得文章不错的话,帮忙点一个赞 👍 吧, 感谢
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。