我有酒你有故事系列,以TS视角通过案例(故事
)贯穿全文,希望能帮助你更加了解TS
本文主要对TS加深理解,如果您还不认识TypeScript请移步 入门教程 或 官方网站
TypeScript关键字
in
用来取出(遍历)联合类型的每一个成员类型
interface Original {
name: string;
age: number;
}
type ReadonlyOriginal = { readonly [K in keyof Original]: Original[K]; };
const readonlyOriginal: ReadonlyOriginal = { name: 'David', age: 35 };
readonlyOriginal.age = 36;// 这将导致错误,因为属性是只读的
keyof
用于将对象类型的键组合成一个联合类型
interface User {
name: string;
age: number;
location?: string;
}
type RequiredUser = {
[K in keyof User]-?: User[K]; // 使所有属性都成为必填
};
const requiredUser: RequiredUser = {
name: 'Alice',
age: 30,
location: 'New York'
};
readonly
可以防止对象的属性被更改
interface User {
name: string;
age: number;
}
type ReadonlyUser = {
readonly [P in keyof User]: User[P];
};
const user: User = { name: 'Alice', age: 30 };
const readonlyUser: ReadonlyUser = { name: 'Alice', age: 30 };
readonlyUser.age = 31; // 编译错误:属性是只读的
infer
类型推断
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
function greet(name: string): string {
return `Hello, ${name}`;
}
const greetReturnType: ReturnType<typeof greet>; // 结果是 string
declare
用于声明全局变量、函数、类或模块
- 声明全局变量
// 假设这是一个在全局范围内的变量
declare var globalConfig: { apiKey: string; apiBaseURL: string };
globalConfig.apiKey = 'my-api-key';
- 声明全局函数
declare function fetch(url: string, init?: RequestInit): Promise<Response>;
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data));
- 声明命名空间
declare namespace MyLib {
interface Settings {
theme: string;
language: string;
}
function setSettings(settings: Settings): void;
}
// 使用声明的命名空间
MyLib.setSettings({ theme: 'dark', language: 'en' });
- 声明模块
declare module 'lodash' {
function compact<T>(array: Array<T | null | undefined>): T[];
export = compact;
}
import compact from 'lodash';
const filtered = compact([1, null, 2, undefined, 3]);
- 声明类型和接口
// 在一个.d.ts文件中
declare type User = {
id: number;
name: string;
};
// 使用声明的类型
const user: User = { id: 1, name: 'John Doe' };
内置函数
Pick
从一个接口或类型中选择特定的属性并创建一个新的类型
interface UserInfo {
name: string;
email: string;
password: string;
age: number;
address: string;
}
type UserSummary = Pick<UserInfo, 'name' | 'email' | 'age'>;
const user: UserInfo = {
name: 'Alice',
email: 'alice@example.com',
password: 'secret',
age: 30,
address: '123 Main St.'
};
const summary: UserSummary = {
name: user.name,
email: user.email,
age: user.age
};
Readonly
会接收一个泛型参数,并返回一个完全一样的类型,只是所有属性都会是只读 (readonly) 的
interface UserConfig {
theme: string;
language: string;
}
const config: Readonly<UserConfig> = {
theme: 'dark',
language: 'en-US'
};
// config.theme = 'light'; // 尝试修改时,编译器会报错
Exclude
从联合类型 T
中排除 U
中的类型,来构造一个新的类型
type NullableStringOrNumber = string | number | null;
type NotNull = Exclude<NullableStringOrNumber, null>;
const value: NotNull = 'Hello'; // OK
const value2: NotNull = 123; // OK
const value3: NotNull = null; // Error: Type 'null' is not assignable to type 'NotNull'.
Parameters
从一个函数类型中抽取参数类型,并将其作为一个元组类型返回
function sum(a: number, b: number): number {
return a + b;
}
type SumParameters = Parameters<typeof sum>; // 结果是 [a: number, b: number]
const params: SumParameters = [1, 2];
ReturnType
从函数类型中抽取返回类型
function getUser(id: number): { name: string; age: number } {
return { name: 'John Doe', age: 30 };
}
type UserType = ReturnType<typeof getUser>;
const user: UserType = getUser(1);
Omit
从一个类型中删除某些属性,创建一个新的类型
interface User {
id: number;
name: string;
password: string;
creditCardNumber: string;
}
type PublicUser = Omit<User, 'password' | 'creditCardNumber'>;
const user: User = {
id: 1,
name: 'Alice',
password: 'secret',
creditCardNumber: '1234-5678-9012-3456'
};
const publicUser: PublicUser = {
id: user.id,
name: user.name
};
Required
用于将一个类型中的所有可选属性变为必需属性
interface User {
id: number;
name: string;
email?: string;
phone?: string;
}
type RequiredUser = Required<User>;
const user: RequiredUser = {
id: 1,
name: 'Alice',
email: 'alice@example.com',
phone: '123-456-7890'
};
// 下面的代码将会在编译时失败,因为 email 和 phone 是必需的
// const invalidUser: RequiredUser = {
// id: 2,
// name: 'Bob'
// };
Partial
可以把一个接口或类型中的所有属性变成可选的
interface User {
id: number;
name: string;
email: string;
address: {
street: string;
city: string;
country: string;
};
}
type PartialUser = Partial<User>;
let user: PartialUser = {};
// 逐步填充数据
user.id = 1;
user.name = 'Alice';
user.email = 'alice@example.com';
user.address = { street: '123 Main St', city: 'Anytown' };
// 后续可以继续添加 country 字段
user.address.country = 'USA';
Record
创建一个具有特定键和值类型的对象
type CurrencyConfig = Record<'USD' | 'EUR' | 'JPY', string>;
const currencySymbols: CurrencyConfig = {
USD: '$',
EUR: '€',
JPY: '¥'
};
常用案例
类型断言
function getLength(x: string | number): number {
if((x as string).length){
return (<string>x).length
}else{
return x.toString().length
}
}
筛选出所有可选属性
type GetOption<T> = {
[P in keyof T as T[P] extends Required<T>[P] ? never : P]: T[P];
};
对防抖函数进行类型标注
declare function debounce<A extends any[], R>(
fn: (...args: A) => R,
duration?: number
): (...args: A) => void;
深度只读
type DeepReadonly<T extends Record<string|symbol, any>>={
readonly [K in keyof T]: DeepReadonly<T[K]>;
}
联合类型转交叉类型
type UnionToIntersection<T>=
(T extends any ? (x:T) => any: never) extends
(x: infer R) => any ? R : never;
筛选对象属性值为string与number
type StoreKeys<T> = {
[K in keyof T]: T[K] extends string | number ? K : never;
}[keyof T];