Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

typescript内置工具类型、实用技巧及tsconfig配置释义 #33

Open
oliveying opened this issue Jul 18, 2023 · 0 comments
Open

Comments

@oliveying
Copy link
Owner

oliveying commented Jul 18, 2023

typeof

  • typeof 关键词除了做类型保护 还可以从实现推出类型
//先定义变量,再定义类型
let p1 = {
  name: "olive",
  age: 18,
  skill: ['code'],
};
type People = typeof p1;
function getName(p: People): string {
  return p.name;
}
getName(p1);

keyof 关键词

  • keyof 可以用来取得一个对象接口的所有 key 值
interface Person {
    name?: string,
    age?: number,
    skill: string[]
}
//type PersonKey = 'name'|'age'|'skill';
// type PersonKey = keyof Person; 使用keyof操作符时,需要传入一个类型而不是一个值

type PersonKey = keyof typeof Person
function getValueByKey(p: Person, key: PersonKey) {
  return p[key];
}
let val = getValueByKey({ name: "olive", age: 10, skill: ['code'] }, "name");
console.log(val);

索引访问操作符

  • 使用 [] 操作符可以进行索引访问
  interface Person {
  name: string;
  age: number;
}

type x = Person["name"]; // x is string

映射类型 in

  • 在定义的时候用 in 操作符去批量定义类型中的属性
interface Person {
  name: string;
  age: number;
  skill: string[]
}
//批量把一个接口中的属性都变成可选的
type PartPerson = {
  [Key in keyof Person]?: Person[Key];
};

let p1: PartPerson = {};

infer 关键字

  • 在条件类型语句中,可以用 infer 声明一个类型变量并且对它进行使用。
    用它取到函数返回值的类型方便之后使用。
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

内置工具

1. Required

  • 将传入的属性中的可选项变为必选项,这里用了 -? 修饰符来实现。
interface Person {
    name?: string,
    age?: number,
    skill: string[]
}
/**
 * type Required<T> = { [P in keyof T]-?: T[P] };
 */
const user: Required<Person> = {
    name: 'olive',
    age: 18,
    skill: ['code']
}

2. Partial

  • 与 Required 相反,将传入的属性由非可选变为可选
type Partial<T> = { [P in keyof T]?: T[P] };

interface A {
  a1: string;
  a2: number;
  a3: boolean;
}
type aPartial = Partial<A>;
const a: aPartial = {}; // 编译正确,不会报错

3. Exclude

  • Exclude<T,U> 从 T 可分配给的类型中排除 U
type Exclude<T, U> = T extends U ? never : T;

type E = Exclude<string | number, string>;
let e: E = 10;

// 例子
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number

4. Extract

  • 和 Exclude 相反,Extract<T,U> 从 T 中提取出 U。适用于并集类型
type Extract<T, U> = T extends U ? T : never;

type E = Extract<string | number, string>;
let e: E = "1";

// 例子
type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T1 = Extract<string | number | (() => void), Function>; // () =>void

5. Readonly

  • Readonly 通过为传入的属性每一项都加上 readonly 修饰符来实现。
interface Person {
  name: string;
  age: number;
  skill: string[],
}
//type Readonly<T> = { readonly [P in keyof T]: T[P] };
let p: Readonly<Person> = {
  name: "duruo",
  age: 18,
  skill: ['code'],
};
p.age = 20; //error

6. Pick

Pick<T,K>Pick 能够帮助我们从传入的属性中摘取某些返回

type Person = {
  name: string;
  age:number;
  skill: ['code'],
}

/**
 * From T pick a set of properties K
 * type Pick<T, K extends keyof T> = { [P in K]: T[P] };
 */
type P1 = Pick<Person, "name" | "age">; // { name: string; age: number; }

const user:P1={
  name:'olive',
  age:18
}

7. Omit

  • 与Pick相反,Omit<K,T> 基于已经声明的类型进行属性剔除获得新类型
// type Omit=Pick<T,Exclude<keyof T,K>>

interface Person {
  name: string,
  age: number,
  skill: string
}
type P1 = Omit<Person, "age" | "skill">
const user:P1  = {
  name: 'olive'
}

8. Record

Record<K,T> 构造一个类型,该类型具有一组属性 K,每个属性的类型为 T。可用于将一个类型的属性映射为另一个类型。Record 后面的泛型就是对象键和值的类型。

  • 简单理解:K 对应的 key,T 对应对象的 value,返回的就是一个声明好的对象 但是 K 对应的泛型约束是keyof any 也就意味着只能传入 string|number|symbol
// type Record<K extends keyof any, T> = {
// [P in K]: T;
// };
type Point = "x" | "y";
type PointList = Record<Point, { value: number }>;
const cars: PointList = {
  x: { value: 10 },
  y: { value: 20 },
};

// 另
type Property = 'key1'|'key2'
type Person = Record<Property, string>;

const p: Person = {
  key1: "嘿嘿",
  key2: "你好",
};

9. NonNullable

  • 从 T 中排除 null 和 undefined
type NonNullable<T> = T extends null | undefined ? never : T;

type P1 = NonNullable<string | number | undefined>; // string | number
type P2 = NonNullable<string[] | null | undefined>; // string[]

10. ReturnType

  • 用来得到一个函数的返回值类型
type ReturnType<T extends (...args: any[]) => any> = T extends (
  ...args: any[]
) => infer R
  ? R
  : any;
function getUserInfo() {
  return { name: "olive", age: 10 };
}

// 通过 ReturnType 将 getUserInfo 的返回值类型赋给了 UserInfo
type UserInfo = ReturnType<typeof getUserInfo>;

const userA: UserInfo = {
  name: "olive",
  age: 18,
};

// 另
type Func = (value: string) => string;
const test: ReturnType<Func> = "1";

11. Parameters

  • 用于获得函数的参数类型所组成的元组类型。
type Parameters<T> = T extends (...args: infer R) => any ? R : any;

type T0 = Parameters<() => string>; // []
type T1 = Parameters<(s: string) => void>; // [string]
type T2 = Parameters<<T>(arg: T) => T>; // [unknown]

// 另
type P1 = Parameters<(a: number, b: string) => void>; // [number, string]

类型保护

  • 类型保护就是一些表达式,他们在编译的时候就能通过类型信息确保某个作用域内变量的类型 其主要思想是尝试检测属性、方法或原型,以确定如何处理值

typeof 类型保护

function double(input: string | number | boolean) {
  if (typeof input === "string") {
    return input + input;
  } else {
    if (typeof input === "number") {
      return input * 2;
    } else {
      return !input;
    }
  }
}

in关键字

interface Bird {
  fly: number;
}

interface Dog {
  leg: number;
}

function getNumber(value: Bird | Dog) {
  if ("fly" in value) {
    return value.fly;
  }
  return value.leg;
}

instanceof 类型保护

class Animal {
  name!: string;
}
class Bird extends Animal {
  fly!: number;
}
function getName(animal: Animal) {
  if (animal instanceof Bird) {
    console.log(animal.fly);
  } else {
    console.log(animal.name);
  }
}

自定义类型保护

  • 通过 type is xxx这样的类型谓词来进行类型保护

例如下面的例子 value is object就会认为如果函数返回 true 那么定义的 value 就是 object 类型

function isObject(value: unknown): value is object {
  return typeof value === "object" && value !== null;
}

function fn(x: string | object) {
  if (isObject(x)) {
    // ....
  } else {
    // .....
  }
}

tsconfig.json

npm install -g  typescript # 全局安装 ts

tsc -v  # 版本号
tsc --init # 生成tsconfig.json 配置文件

tsconfig.json

tsconfig.json 的作用

  • 用于标识 TypeScript 项目的根路径;
  • 用于配置 TypeScript 编译器;
  • 用于指定编译的文件。

重要字段

  • files - 设置要编译的文件的名称;
  • include - 设置需要进行编译的文件,支持路径模式匹配;
  • exclude - 设置无需进行编译的文件,支持路径模式匹配;
  • compilerOptions - 设置与编译流程相关的选项。

compilerOptions 选项

{
  "compilerOptions": {

    /* 基本选项 */
    "target": "es5",                       // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
    "module": "commonjs",                  // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
    "lib": [],                             // 指定要包含在编译中的库文件
    "allowJs": true,                       // 允许编译 javascript 文件
    "checkJs": true,                       // 报告 javascript 文件中的错误
    "jsx": "preserve",                     // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
    "declaration": true,                   // 生成相应的 '.d.ts' 文件
    "sourceMap": true,                     // 生成相应的 '.map' 文件
    "outFile": "./",                       // 将输出文件合并为一个文件
    "outDir": "./",                        // 指定输出目录
    "rootDir": "./",                       // 用来控制输出目录结构 --outDir.
    "removeComments": true,                // 删除编译后的所有的注释
    "noEmit": true,                        // 不生成输出文件
    "importHelpers": true,                 // 从 tslib 导入辅助工具函数
    "isolatedModules": true,               // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).

    /* 严格的类型检查选项 */
    "strict": true,                        // 启用所有严格类型检查选项
    "noImplicitAny": true,                 // 在表达式和声明上有隐含的 any类型时报错
    "strictNullChecks": true,              // 启用严格的 null 检查
    "noImplicitThis": true,                // 当 this 表达式值为 any 类型的时候,生成一个错误
    "alwaysStrict": true,                  // 以严格模式检查每个模块,并在每个文件里加入 'use strict'

    /* 额外的检查 */
    "noUnusedLocals": true,                // 有未使用的变量时,抛出错误
    "noUnusedParameters": true,            // 有未使用的参数时,抛出错误
    "noImplicitReturns": true,             // 并不是所有函数里的代码都有返回值时,抛出错误
    "noFallthroughCasesInSwitch": true,    // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)

    /* 模块解析选项 */
    "moduleResolution": "node",            // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
    "baseUrl": "./",                       // 用于解析非相对模块名称的基目录
    "paths": {},                           // 模块名到基于 baseUrl 的路径映射的列表
    "rootDirs": [],                        // 根文件夹列表,其组合内容表示项目运行时的结构内容
    "typeRoots": [],                       // 包含类型声明的文件列表
    "types": [],                           // 需要包含的类型声明文件名列表
    "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。

    /* Source Map Options */
    "sourceRoot": "./",                    // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
    "mapRoot": "./",                       // 指定调试器应该找到映射文件而不是生成文件的位置
    "inlineSourceMap": true,               // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
    "inlineSources": true,                 // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性

    /* 其他选项 */
    "experimentalDecorators": true,        // 启用装饰器
    "emitDecoratorMetadata": true          // 为装饰器提供元数据的支持
  }
}

默认index.d.ts设置

declare module '*.less' {
  const resource: { [key: string]: string };
  export = resource;
}

declare module '*.png';

declare module '*.jpg';

/** 通过infer获取arrayType 数组的item类型 */
declare type GetArrayType<T> = Exclude<T, undefined> extends Array<infer P> ? P : unknown;

/** 获取函数的参数类型 */
declare type GetFuncParam<T> = T extends (param: infer P) => void ? P : unknown;

/**
 * 通过对象
 * ```
 * [propName: string]: any;
 * ```
 */
declare interface IPlainObject {
  [propName: string]: any;
}

/**
 * 一般用于select option的类型
 * ```ts
 * {
 *  key: string;
    value: any;
    label: string;
 * }
 * ```
 */
declare interface ISelectOption {
  key: string | number;
  value: any;
  label: string;
}

参考 https://tsejx.github.io/typescript-guidebook/syntax/advanced/type-guards#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%9E%8B%E4%BF%9D%E6%8A%A4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant