开发者社区 > 博文 > TypeScript 请讲出你的故事
分享
  • 打开微信扫码分享

  • 点击前往QQ分享

  • 点击前往微博分享

  • 点击复制链接

TypeScript 请讲出你的故事

  • xi****
  • 2024-08-27
  • IP归属:北京
  • 100浏览

    我有酒你有故事系列,以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];


    文章数
    1
    阅读量
    0

    作者其他文章