整理一些好用的TS写法

1. 工具类型

Partial

所有的字段都会被成可选的

typescript 复制代码
interface AppConfig {
  title: string;
  version: number;
  theme: 'light' | 'dark';
}

type PartialConfig = Partial<AppConfig>;
// Equivalent to: { title?: string; version?: number; theme?: 'light' | 'dark'; }
Pick

从一个类型中选中指定属性

typescript 复制代码
interface AppConfig {
  title: string;
  version: number;
  theme: 'light' | 'dark';
}

type TitleConfig = Pick<AppConfig, 'title' | 'version'>;
// Equivalent to: { title: string; version: number; }
Omit

从一个类型中排除指定属性

typescript 复制代码
interface AppConfig {
  title: string;
  version: number;
  theme: 'light' | 'dark';
}

type WithoutTheme = Omit<AppConfig, 'theme'>;
// Equivalent to: { title: string; version: number; }
Readonly

将所有属性变为只读

typescript 复制代码
interface AppConfig {
  title: string;
  version: number;
  theme: 'light' | 'dark';
}

type ReadonlyConfig = Readonly<AppConfig>;
// Equivalent to: { readonly title: string; readonly version: number; readonly theme: 'light' | 'dark'; }
Required

将所有属性变为必选

typescript 复制代码
type RequiredConfig = Required<{
  description?: string | null;
}>;
// Equivalent to: { description: string | null; }

这里要注意:

description?: string | nulldescription: string | null | undefined 是不一样的。

前一个代表 description 是可选的,后一个代表 description 的值可能是 undefined

Required 只会移除 ?, 而不会去处理 undefined

ts 复制代码
type RequiredConfig = Required<{
  description: string | null | undefined;
}>;
// Equivalent to: {  description: string | null | undefined; }
Record

创建一个对象类型,键为指定的类型,值为指定的类型

ts 复制代码
type RecordConfig = Record<'vueApp' | 'ngApp', AppConfig>;
// Equivalent to: { vueApp: AppConfig; ngApp: AppConfig; }
Exclude

从联合类型中排除指定的类型

ts 复制代码
type ExcludeConfig = Exclude<'a' | 'b' | 'c', 'b' | 'd'>;
// Equivalent to: 'a' | 'c'
Extract

从联合类型中提取交集的类型

ts 复制代码
type ExtractConfig = Extract<'a' | 'b' | 'c', 'b' | 'd'>;
// Equivalent to: 'b'
NonNullable:

从联合类型中排除 null 和 undefined

ts 复制代码
type NonNullableUnitType = NonNullable<string | null | undefined>;
// Equivalent to: string

但是它无法对类型进行非空处理

ts 复制代码
type NonNullableType = NonNullable<{
  description: string | null | undefined;
}>;
// 你预期的结果: { description: string; }
// 实际结果: { description: string | null | undefined; }

可以基于 NonNullable Map一个新的工具类型,实现上述需求

ts 复制代码
type NonNullablePlus<T> = {
  [K in keyof T]: NonNullable<T[K]>;
};

type NonNullableType = NonNullablePlus<{
  description: string | null | undefined;
}>;
// Equivalent to: { description: string; }
Parameters

提取函数参数类型, 返回数组

ts 复制代码
declare function f1(arg: { a: number; b: string }, arg2: string): void;
type F1Parameters = Parameters<typeof f1>;
// Equivalent to: [arg: { a: number; b: string; }, arg2: string]

type T1 = Parameters<() => void>;
// Equivalent to: []
ConstructorParameters

提取类的构造函数参数, 返回数组

ts 复制代码
class C {
  constructor(a: number, b: string) {}
}
type TCConstructorParameters = ConstructorParameters<typeof C>;
// Equivalent to: [a: number, b: string]
ReturnType

提取函数返回值类型

ts 复制代码
declare function f1(): { a: number; b: string };;
type F1ReturnType = ReturnType<typeof f1>;
// Equivalent to: { a: number; b: string; }
InstanceType

提取类的类型

ts 复制代码
class C {
  x = 0;
  y = 0;
  constructor(a: number, b: string) {}
}
type CType = InstanceType<typeof C>;
// Equivalent to: C
NoInfer
  1. 强制用户显式的指定泛型类型
ts 复制代码
function useValue<T>(value: NoInfer<T>): T {
  return value;
}

const explicitValue = useValue<string>("hello"); // OK
const inferredValue = useValue("hello"); // Error: 必须显式的指定类型
  1. 防止泛型类型推断
ts 复制代码
function createStreetLight<C extends string>(
  colors: C[],
  defaultColor?: NoInfer<C>,
) {
  // ...
}
createStreetLight(["red", "yellow"], );  // OK
createStreetLight(["red", "yellow", "green"], "blue");  // Error

这里,NoInfer<C> 确保 defaultColor 的类型必须显式匹配 C,而不会被推断为其他类型。

  1. 防止默认类型被覆盖
ts 复制代码
function createStore<T = { default: true }>(state: NoInfer<T>): T {
  return state;
}

const store = createStore(); // 类型为 { default: true }
const customStore = createStore({ custom: true }); // Error: 类型推断被阻止

2. 模板字面量类型

它可以基于字符串模板创建类型。

Capitalize<StringType> 可以将字符串字面量类型的第一个字符转换为大写。

typescript 复制代码
type Event = 'click' | 'hover';
type EventHandler = `on${Capitalize<Event>}`;

const handler: EventHandler = 'onClick'; // 或 'onHover'

除了 Capitalize 外,还有其它几个

  • Uncapitalize<StringType> :将字符串字面量类型的第一个字符转换为小写。
  • Uppercase<StringType>:将字符串字面量类型的所有字符转换为大写。
  • Lowercase<StringType> :将字符串字面量类型的所有字符转换为小写。

你可以结合 keyof 自己创建一些更有用的工具类型

ts 复制代码
type UppercaseKeys<T> = {
  [K in keyof T as Uppercase<K & string>]: T[K];
};

type Example = UppercaseKeys<{ name: string; age: number }>;
// Equivalent to: { NAME: string; AGE: number }

3. keyof

3.1 获取对象类型的键

ts 复制代码
type Person = {
  name: string;
  age: number;
  isStudent: boolean;
};

type PersonKeys = keyof Person;
// Equivalent to: 'name' | 'age' | 'isStudent'

3.2 使用 keyof 限制键的类型

ts 复制代码
function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const person = { name: 'Alice', age: 25 };

const name = getValue(person, 'name'); // OK, 返回类型为 string
const age = getValue(person, 'age'); // OK, 返回类型为 number
// const invalid = getValue(person, 'height'); // Error: 类型 '"height"' 不可分配给参数

3.3 map 类型

可以用 Partial 作为例子

ts 复制代码
/**
 * Make all properties in T required
 */
type Required<T> = {
    [P in keyof T]-?: T[P];
};

这里 -? 的作用是从属性中移除可选标记(?)。它的作用是将类型中的所有可选属性变为必选属性。

4. infer

它用于条件中的类型推导。

Typescript 官网拿 ReturnType 这一经典例子来演示它的作用

ts 复制代码
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

如果 T 继承了 (...args: any[]) => any 类型,则返回类型 R,否则返回 any。其中的 R 是从传入参数类型中推导出来的,infer相当于一个类型占位。

可以结合上面 ReturnType 中的例子来看

ts 复制代码
declare function f1(): { a: number; b: string };;
type F1ReturnType = ReturnType<typeof f1>;
// Equivalent to: { a: number; b: string; }

5. as const

as const 将一个对象或数组的所有属性变为 只读 ,并将其值的类型从宽泛的类型(如 stringnumber)缩小为更具体的类型(如 'value'1)。

ts 复制代码
const data = { age: 1 };
type DataType =  typeof data;
// Equivalent to: { age: number; }

const dataConst = { age: 1 } as const;
type DataConstType =  typeof dataConst;
// Equivalent to: { readonly age: 1; }

它可以与 typeof 一起使用,从常量中提取更具体的类型。

ts 复制代码
const COLORS = {
  RED: 'red',
  GREEN: 'green',
  BLUE: 'bl?

type Color = typeof COLORS[keyof typeof COLORS];
// Equivalent to: 'red' | 'green' | 'blue'


const directions = ['up', 'down', 'left', 'right'] as const;

type Direction = typeof directions[number];
// Equivalent to: 'up' | 'down' | 'left' | 'right'

6. 泛型约束

通过 extends 关键字,可以对泛型进行约束,限制泛型的类型范围。

ts 复制代码
function getLength<T extends { length: number }>(arg: T): number {
  return arg.length;
}

getLength('Hello'); // OK, string 有 length 属性
getLength([1, 2, 3]); // OK, 数组有 length 属性
// getLength(42); // Error: number 没有 length 属性

7. 根据枚举值,动态生成类型

ts 复制代码
enum ShapeType {
    Square = 1,
    Circle = 2
}

interface Square {
    size: number;
}

interface Circle {
    radius: number;
}

type MutableRecord<T> = {
  [SubType in keyof T]: {
    type: SubType;
  } & { [K in keyof T[SubType]]: T[SubType][K] };
}[keyof T];

type Shape = MutableRecord<{
  [ShapeType.Square]: Square;
  [ShapeType.Circle]: Circle;
}>;

const circle: Shape = {
  type: ShapeType.Circle,
  radius: 1, // 这里只会出现 radius
};
const square: Shape = {
  type: ShapeType.Square,
  size: 1, // 这里只会出现 size
};

持续更新中...

相关推荐
少糖研究所1 分钟前
ColorThief库是如何实现图片取色的?
前端
冴羽1 分钟前
SvelteKit 最新中文文档教程(22)—— 最佳实践之无障碍与 SEO
前端·javascript·svelte
ZYLAB3 分钟前
我写了一个简易的 SEO 教程,希望能让新手朋友看完以后, SEO 能做到 80 分
前端·seo
小桥风满袖9 分钟前
Three.js-硬要自学系列4 (阵列立方体和相机适配、常见几何体、高光材质、lil-gui库)
前端·css
深海丧鱼11 分钟前
什么!只靠前端实现视频分片?
前端·音视频开发
ohMyGod_12313 分钟前
Vue如何实现样式隔离
前端·javascript·vue.js
涵信17 分钟前
第二十节:项目经验-描述一个React性能优化案例
前端·react.js·性能优化
Danny_FD23 分钟前
前端中的浮动、定位与布局
前端·css
Abadbeginning26 分钟前
vue3后台管理框架geeker admin 横向布局(了解)
前端·javascript·vue.js
OpenTiny社区28 分钟前
直播分享|TinyVue 多端实战与轻量图标库分享
前端·vue.js·开源