Typescripts从入门到精通

154 阅读5分钟

highlight: a11y-dark

基础知识点

全局安装编译 TS 的工具

安装包:npm i -g typescript
//通过tsc ts文件进行编译,生成一个新的js文件
tsc hello.ts

为了方便不用每次编译生成新文件安装ts-node包:

npm i -g ts-node
//运行文件node hello.ts
//ts-node报错问题
Cannot find name 'console'. Do you need to change your target library? Try changing thelibcompiler option to include 'dom'.
解决方法:
目录下运行 tsc --init 生成配置文件tsconfig.json

原始类型

// 基础数据类型
let age: number = 18;
let myName: string = "小江";
let isLoading: boolean = true;
let un: undefined = undefined;
let timer: null = null;

联合类型

// | 联合类型

// 联合类型1: 变量可以是两种类型之一
let timer:number|null = null
timer = 2

// 联合类型2: 数组元素可以是两种类型之一
let arr: (number|string|boolean)[] = [1,2,3]

arr[0] = '1'
arr[2] = true

数组类型

// 数组
let arr: (number | string)[] = [1, 2, "3"];

let arr2: Array<number | string | boolean> = [1, 2, "3", true];

类型别名

type myNum = number;
let num: myNum = 1;

函数

// 普通函数
function 函数名(形参1: 类型=默认值, 形参2:类型=默认值): 返回值类型 { }

// 箭头函数
const 函数名(形参1: 类型=默认值, 形参2:类型=默认值):返回值类型 => { }

对象类型

// 创建类型别名
type Person = {
  name: string,
  age: number
  sayHi(): void
}

// 使用类型别名作为对象的类型:
let person: Person = {
  name: '小花',
  age: 18
  sayHi() {}
}

function f1 (p: Persion) :void {
  
}


接口类型

interface IGoodItem  {
    name: string, price: number, func: ()=>string
}


const good1: IGoodItem = {
    name: '手表',
    price: 200,
    func: function() {
        return '看时间'
    }
}

const good2: IGoodItem = {
    name: '手机',
    price: 2000,
    func: function() {
        return '打电话'
    }
}

interface 和type的区别

  • 相同点:都可以给对象指定类型
  • 不同点 interface只能指定类型,可以继承;type不仅可以给对象指定类型,还可以给任意类型指定别名

接口继承

interface Point2D { x: number; y: number }
// 继承 Point2D
interface Point3D extends Point2D {
  z: number
}

元组

元组是另一种特殊的数组

  • 它确切地包含多少个元素
  • 特定索引对应的类型
let position: [number, number] = [39.5427, 116.2317]

字面量类型

// 第一种
type ActionType = 'ADD_TODO' | 'DEL_TODO'
function reducer(type:ActionType) {
  if(type === 'ADD_TODO')
}
// 第二种
type Direction = 'up' | 'down' | 'left' | 'right'

function changeDirection(direction: Direction) {
  console.log(direction)
}

// 调用函数时,写上'',就会有类型提示:
changeDirection('up')

枚举类型

// 数字枚举
// Down -> 11、Left -> 12、Right -> 13
enum Direction { Up = 10, Down, Left, Right }

enum Direction { Up = 2, Down = 4, Left = 8, Right = 16 }
// 字符串枚举
enum Direction {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT'
}
//使用场景
enum Gender {
    girl,
    boy
}
type User = {
    name: string,
    gender: Gender
}
const u1: User = {
    name: '小花',
    gender: Gender.girl
}
console.log(u1)

any类型

any:任意类型,使用后这会让 TypeScript 变为 “AnyScript”(失去 TS 类型保护的优势)

其他

  • as:类型断言
type User = {
  name: string,
  age: number
}

const u1 = {} as User

console.log(u1.name) // 这里就会有提示

  • typeof

使用 typeof 操作符来获取变量 p 的类型,结果与第一种(对象字面量形式的类型)相同

const res = { name: '小花', city: '武汉',  skills: ['js', 'css'] }

type Stu = typeof res

function fn(obj:Stu) {
    // 这里写 obj. 就会有提示
    obj.skills
}

fn(res)

  • keyof

keyof 索引查询

对应任何类型T,keyof T的结果为该类型上所有公有属性key的联合:

interface Eg1 {
name: string,
readonly age: number,
}
// T1的类型实则是name | age
type T1 = keyof Eg1

class Eg2 {
private name: string;
public readonly age: number;
protected home: string;
}
// T2实则被约束为 age
// 而name和home不是公有属性,所以不能被keyof获取到
type T2 = keyof Eg2
  • infer

表示在extends条件语句中待推断得类型变量

type Union<T> = T extends Array<infer U> ? U: never

ts进阶知识

ts内置类型工具分析

Partial原理分析

// Partial原理

type PartialNew<T> = {
  [P in keyof T]?: T[P];
};

// 扩展Partial
type PartialNewOption<T, Key extends keyof T> = {
  [P in Key]?: T[P];
};
type a1 = PartialNewOption<IObj4, "name" | "sex" | "age" | "isCn">;

Readonly原理分析

// Readonly原理
type ReadonlyNew<T> = {
  readonly [P in keyof T]: T[P];
};
// Readonly原理扩展
type ReadonlyNewOption<T, Key extends keyof T> = {
  readonly [P in Key]: T[P];
};
type a2 = ReadonlyNewOption<IObj4, "name" | "id" | "age">;

Pick原理分析

Pick原理
type PickNew<T, Key extends keyof T> = {
  [P in Key]: T[P];
};
type a3 = PickNew<IObj4, "name" | "id" | "sex" | "age">;

Record原理分析

// Record原理
type typeRecordNew<K extends keyof any,T>={
    [P in K]:T
}

type Type = 'a'|'b'|'c'|'d'|'e'|'f'
type a4 = typeRecordNew<Type,{key1:string}>

Exclude原理分析

// Exclude原理 取存在Type,不存在Type2的值
type Type2='a'| 'b'|'h'|'i'|'j'
type ExcludeNew<T,U>=T extends U?never:T
type a5 =ExcludeNew<Type,Type2>

Extract原理分析

// Extract原理  取Type和Type2相同值
type ExtractNew<T,U>=T extends U?T:never
type a6 = ExtractNew<Type,Type2>

Omit原理分析

//Omit原理
type OmitNew<T,K extends keyof T>={
    [P in ExcludeNew<keyof T,K>]:T[P]
}
type a7 = OmitNew<IObj4,'id'>
//第二种方式,利用Pick
type a8 =Pick<IObj4,ExcludeNew<keyof IObj4,'id'|'sex'>>

Parameters原理分析

// 获取函数的参数类型
type ParametersNew<T extends (...args:any)=>any>=T extends (...arg:infer P)=>any?P:never
type FalttenArray<T extends Array<any>>=T extends Array<infer P>?P:never

type a9 =ParametersNew<(name:string,age:number)=>void>
type a9 =ParametersNew<(name:string,age:number)=>void>
function getUser1(aa:number) {
    return {name: 'xxx', age: aa}
  }
  
  type GetUserType1 = typeof getUser1;
  type ReturnUser1 = Parameters<GetUserType1>

ReturnType原理分析


// 获取返回值类型
type ReturnTypeNew<T extends (...args:any)=>any>=T extends (...args:any)=>infer P ?P:any

type a11=ReturnTypeNew<()=> number >

function getUser() {
    return {name: 'xxx', age: 10}
  }
  
  type GetUserType = typeof getUser;
  type ReturnUser = ReturnType<GetUserType>
  • infer关键词作用是让Ts自己推导类型,并将推导结果存储在其参数绑定的类型上。Eg:infer P 就是将结果存在类型P上,供使用。
  • infer关键词只能在extends条件类型上使用,不能在其他地方使用。

其他内部实现的类型

type Uppercase<S extends string> = intrinsic;
type Lowercase<S extends string> = intrinsic;
type Capitalize<S extends string> = intrinsic;
type Uncapitalize<S extends string> = intrinsic;

UpperCase
/**
 * @desc 构造一个将字符串转大写的类型
 * @example
 * type Eg1 = 'ABCD';
 */
type Eg1 = Uppercase<'abcd'>;


Lowercase
/**
 * @desc 构造一个将字符串转小大写的类型
 * @example
 * type Eg2 = 'abcd';
 */
type Eg2 = Lowercase<'ABCD'>;


Capitalize
/**
 * @desc 构造一个将字符串首字符转大写的类型
 * @example
 * type Eg3 = 'abcd';
 */
type Eg3 = Capitalize<'Abcd'>;


Uncapitalize
/**
 * @desc 构造一个将字符串首字符转小写的类型
 * @example
 * type Eg3 = 'ABCD';
 */
type Eg3 = Uncapitalize<'aBCD'>;


NonNullable
  • NonNullable:去掉T中的努力了和undefined;T为字面量/具体类型的联合类型,如果是对象类型是没效果的
type T1 = NonNullable<string | number | undefined>;
// type T1 = string | number

type T2 = NonNullable<string[] | null | undefined>;    
// type T2 = string[]

type T3 = {
    name: string
    age: undefined
}
type T4 = NonNullable<T3> // 对象是不行的
自定义
type User1 = {
    my_name: string
    my_age_type: number // 多个下划线
    my_children: {
        my_boy: number
        my_girl: number
    }
}

// 实现如下
type T1<T> = T extends string
	? T extends `${infer A}_${infer B}`
		? `${A}${T1<Capitalize<B>>}` // 这里有递归处理单个属性名多个下划线
		: T
	: T;
// 对象不递归
// type T2<T> = { [P in keyof T as T1<P>]: T[P] }
// 对象递归
type T2<T> = T extends object ? { [P in keyof T as T1<P>]: T2<T[P]> } : T

type T3 = T2<User1>
// type T3 = {
//     myName: string;
//     myAgeType: number;
//     myChildren: {
//         myBoy: number;
//         myGirl: number;
//     };
// }
参考地址