重温Typescript

对TS有些生疏了,想着来总结一波,可作为日后工作中的快速参考手册。

TypeScript具有类型系统,且是JavaScript的超集。

它可以编译成普通的JavaScript代码。 TypeScript支持任意浏览器,任意环境,任意系统并且是开源的。

TS是JS的超集,我的理解是:JS + 类型系统 = TS,对于熟悉JS的同学来说,TS的学习成本很低!

项目引入TS好处也很明显:

  • 让程序更加健壮,更易维护。

  • 在编译器中的类型提示让一些低级错误在编译阶段就被发现。

  • 避免一些无效的沟通。

👂🏻听说你很会Ts? 来,让我看看👁👁!!

初学者建议移步 【TS中文网】 进行学习

若行文有误,欢迎指出👏🏻👏🏻👏🏻

一些准备工作

这些工作更多的是为了测试ts特性。
当然这不是必须的,也可以到 Typescript练习场 去练习和测试。

安装 typescriptts-node 。前者是安装一个ts环境,将编译ts文件为js,方便查看其编译情况,后者支持终端运行ts文件。

npm install -g  typescript # 全局安装 tstsc -v # 查看安装的版本
# Version 5.0.3npm install -g ts-node # 全局安装 ts-nodets-node -v
# v10.9.1

新建一个名 summary 的目录,进入目录新建 helloTS.ts 文件。

mkdir summary
cd summary
touch helloTs.ts

上面步骤进行顺利的话,此时可以初始化目录、编译文件、运行文件了。

helloTs.ts里写下一点想法

const hello: string = '你好,ts, 我顶你个肺啊,哈哈哈'

终端

tsc --init # 初始化,同目录下会生成 tsconfig.json 文件tsc helloTs.ts # 编译,初次运行会在同目录下生成 helloTs.js 文件,这里面就是编译的结果ts-node helloTs.ts # 执行 helloTs.ts 文件,有点像 node xxx.js

tsconfig.json 文件定义着 会对哪些文件进行编译,如何编译(细则,约束),见最后。

基础类型

变量类型声明 是 冒号+ 类型 对一个变量进行类型声明的(废话。

js的八大类型

let str: string = "ethan";
let num: number = 24;
let bool: boolean = false;
let und: undefined = undefined;
let nul: null = null;
let obj: object = {x: 1};
let big: bigint = 100n;
let sym: symbol = Symbol"me"); 

null && undefined

这两个值稍微特殊些,null,undefined 是所有类型的子类型,即可以赋值给任何类型

let obj:object ={};
obj = null;
obj= undefined;const und: undefined = undefined;
const nul: null = null;
let str: string = nul;
let num: number = und;

如果开启严格模式:在 tsconfig.json 指定了 "strict": true,"strictNullChecks":true,运行会抛错,在编译器里就会有提示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传img-xLxjyYGH-1680958995419)/Users/ethanyin/Library/Application%20Support/marktext/images/2023-04-07-17-32-04-image.png)]

let aa: string = nul;// ❌不能将类型“null”分配给类型“string”
let b: number = und;// ❌不能将类型“undefined”分配给类型“number”。

空值(void

void 意思就是无效的, 一般作用在函数上,告诉别人这个函数没有返回值

function sayHello): void {console.log"hello ts");
}

需要注意 null 赋值给 void 值在严格模式下会抛错

let c:void = undefined // 编译正确
let d:void = null // 严格模式下: ❌不能将类型“null”分配给类型“void”

never

never类型表示的是那些永不存在的值的类型。 例如,never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。

// 返回never的函数必须存在无法达到的终点
function errormessage: string): never {throw new Errormessage);
}// 推断的返回值类型为never
function fail) {return error"Something failed");
}// 返回never的函数必须存在无法达到的终点
function infiniteLoop): never {while true) {}
}

枚举(enum

使用枚举我们可以定义一些有名字的数字常量。 枚举通过 enum 关键字来定义。

// 不赋值,默认从0开始~~
// 赋值后即从该值往后 依次累加
enum Anmimal {Cat,// 0Dog = 2,Num = Dog * 2, // 4Bird // 5,G = '123'.length // 计算成员
}
const cat: Anmimal = Anmimal.Cat;
const dog: Anmimal = Anmimal.Dog;
const num: Anmimal = Anmimal.Num;
const bird: Anmimal = Anmimal.Bird;
console.logcat, dog, num, bird) // 0 2 4 5

异构枚举Heterogeneous enums),指枚举值同时出现字符串和数字,尽量避免。

enum BooleanLikeHeterogeneousEnum {No = 0,Yes = "YES",
}

常量枚举constant enum),使用const关键字修饰的常量枚举在编译后会被删除

const enum Color {RED,PINK,BLUE,
}const color: Color[] = [Color.RED, Color.PINK, Color.BLUE];
console.logcolor); //[0, 1, 2]//编译后
var color = [0 /* Color.RED */, 1 /* Color.PINK */, 2 /* Color.BLUE */];
console.logcolor); //[0, 1, 2]

运行时枚举Enums at runtime)

enum E { X, Y, Z }
function fobj: { X: number }) {return obj.X;
}
// Works, since 'E' has a property named 'X' which is a number.
console.logfE)); // 0

编译时枚举Enums at compile time)

enum LogLevel { ERROR, WARN, INFO, DEBUG, }
type LogLevelStrings = keyof typeof LogLevel; // 'ERROR' | 'WARN' | 'INFO' | 'DEBUG'
function printImportantkey: LogLevelStrings, message: string) {const num = LogLevel[key];if num <= LogLevel.WARN) {console.log"Log level key is:", key); // Log level key is: ERRORconsole.log"Log level value is:", num); // Log level value is: 0console.log"Log level message is:", message); // Log level message is:This is a message}
}
printImportant"ERROR", "This is a message");

任意值(any

众所周知,TS的any大法无所不能,哈哈哈~~~~玩笑

当在编程阶段给还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库,那就需要使用any了。

any 类型可赋值给任何类型,并接受任何类型赋值。

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // 可接受二次类型赋值
let str:string = notSure;// any可给任意类型赋值let obj: any = 4;
obj.ifItExists); // ifItExists 方法也许在运行时存在
obj.toFixed); // toFixed 存在 但是编译时不检查)let list: any[] = [1, true, "free"];

unknown

unknownany 一样,所有类型都可以分配给 unknown

let value: unknown = 1;
value = "hello"; 
value = false; 

any 不同的是,unknown 的值只能赋值给 unknown any

let unv: unknown = 1;
let anyv: any = unv;
let str: string = unv; // ❌不能将类型“unknown”分配给类型“string”。

对象类型

在JavaScript中,我们分组和传递数据的基本方式是通过对象。在TypeScript中,我们通过对象类型(泛指)来表示这些类型。

这里的对象很抽象,记得刚学java时,老师说过:“万物皆可为对象~~”。你懂我意思吧😂。

数组

数组两种申明方式

const arr: number[] = [1,2];
const arr1:Array<number> = [1,2]; 

对象类型

这个对象就是实实在在的,具体的,对象分为 objectObject{}

object 仅仅指一个对象,不接受其他基础值的赋值,包括(null, undefined)。

let object: object;
// object = 1; // 报错:不能将类型“number”分配给类型“object”
// object = "a"; // 报错:不能将类型“string”分配给类型“object”。
object = {}; // 编译正确

Object 代表所有拥有 toStringhasOwnProperty 方法的类型,所以所有原始类型、非原始类型都可以赋给 Object严格模式下 null 和 undefined 不可以)。{}同样,可以认为是Object的简写

let bigObj: Object;
bigObj = 1;
bigObj = "a";let normalObj: {};
normalObj = 1;
normalObj = "a";let object: object;
normalObj = {};

{} 和大 Object可以互相代替,用来表示原始类型(null、undefined 除外)和非原始类型;而小 object 则表示非原始类型。object 更像是 Object的子集。

另外注意,除了 Oject大小写可以相互赋值,而其他基础类型(number、string、boolean、symbol)大写赋值给小写会抛错,且没有意义。

❌ Don’t ever use the types Number, String, Boolean, Symbol, or Object These types refer to non-primitive boxed objects that are almost never used appropriately in JavaScript code.


https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#general-types

元祖(Tuple

元组类型允许表示一个 已知元素数量和类型 的数组,各元素的类型不必相同。可以理解为数组的扩充

const tuple: [string, number] = ['哈哈', 1];type Either2dOr3d = [number, number, number?];// number可选// ... 表示0或多个 boolean 值 的元素
type StringNumberBooleans = [string, number, ...boolean[]];
type StringBooleansNumber = [string, ...boolean[], number];
type BooleansStringNumber = [...boolean[], string, number];// 只读元祖
const roTuple: readonly [string, number] = ['哈哈', 1]

扩展类型(Extending Types

对某一个类型 使用 extends 进行扩展

interface BasicAddress {name?: string;street: string;city: string;country: string;postalCode: string;
}interface AddressWithUnit extends BasicAddress {unit: string;
}const liveAdress: AddressWithUnit = {unit: "ts",name: "ethan",street: "secret",city: "secret",country: "china",postalCode: "dont know",
}

交叉类型(Intersection Types

交叉类型 就是跟 联合类型Union Types,后面提到)相反,用 & 操作符表示,交叉类型就是两个类型必须存在

interface PersonA{ // interface 为接口name: string,age: number,birth?: Date; // 生日:YYYY-MM-DDhobby?: "football" | "tennis"; // 爱好 只能为 "football" 或 "tennis"
}interface PersonB {name: string,gender: string
}type PersonAWithBirthDate = PersonA & { birth: Date };let person: PersonA & PersonB = { name: "ethan",age: 18,gender: "男"
};

只读数组(ReadonlyArray Type

此类型的数组不能被改变

const roArray: ReadonlyArray<string> = ["red", "green", "blue"];
roArray[0] = 'change' // ❌类型“readonly string[]”中的索引签名仅允许读取
roArray.push'grey'); // ❌类型“readonly string[]”上不存在属性“push”。

以上情况 与只读修饰符 的效果一样

const roArray: readonly string[] = ["red", "green", "blue"];

最后需要注意的一点是,与只读属性修饰符不同,可赋值性在常规数组和只读数组之间不是双向不可分配/赋值)的。

let xx: readonly string[] = [];
let yy: string[] = [];xx = yy; // ok
yy = xx; // ❌类型 "readonly string[]" 为 "readonly",不能分配给可变类型 "string[]"。roArray = yy; // 因为const定义的。❌类型 "readonly string[]" 为 "readonly",不能分配给可变类型 "string[]"
yy = roArray; // ❌类型 "readonly string[]" 为 "readonly",不能分配给可变类型 "string[]"。

函数

js 的一等公民,使用场景太多了

函数:支持给参数、返回值定义类型;默认参数依然适用 ;?表示y是可选参数

function funcx: number, def: boolean = false, y?: number): number {return y ? x + y : x; // 对于可选参数需要做判断
}// 接口定义函数,后面讲
interface Add {x: number, y: number): number;
}// 声明一个箭头函数,=> 后面number 约定的是返回值类型
let Add: baseValue: number, increment: number) => number =functionx: number, y: number): number { return x + y; };

支持剩余参数定义类型

function restFunc...numbers: number[]): number {let sum = 0;for let i = 0; i < numbers.length; i++) {sum += numbers[i];}return sum;
}

函数重载,函数重载真正执行的是同名函数最后定义的函数体,在最后一个函数体定义之前全都属于函数类型定义 ,不能写具体的函数实现方法,只能定义类型

function addx: number, y: number): number;
function addx: string, y: string): string;
function addx: any, y: any): any {return x + y;
}

约定了add 接收的参数为 一旦有数字或字符串,两个参数必须同为数字或字符串,且返回值也应该为数字或字符串。相当于约定了参数的一致性(入参,出参),当然这里只是演示,并不是说他的作用只有这样,毕竟入参和出参自己定义,但应该是一个强绑定的。

类型推断

对某个变量直接赋值,那么改变量的类型就会被推断为该值的类型

let number = 1;// 被推断为number类型

如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查.

let value;
value = 'ethan';
value = 7;

类型断言

对于某些数据,我比TS更加了解它的类型,那么这时候类型断言就适用。

类型断言: 手动指定一个值的类型

基本语法

支持两种方式

// 方式1
let str: any = "to be or not to be";
let strLength: number = <string>str).length;
// 方式2
let str1: any = "to be or not to be";
let strLength1: number = str1 as string).length;

非空断言

对于多类型的数据,某个场景下无法根据上下文确定其类型,那么非空断言可以支持排除 nullundefined 值,避免使用时不必要的判断。语法是 一个后缀表达符号 !英文感叹号)

// 场景1
let value: null | undefined | string;
value!.toString);
value.toString); // ❌value可能为 “null” 或“未定义”。// 场景2
type funcType = ) => number
function myFuncfunc: funcType | undefined) {const num1 = func); // “func”可能为“未定义”const num2 = func!);
}

确定赋值断言

某个变量被定义后,未赋值前使用就会报错,这时候可以利用确定赋值断言解决。相当于告诉TS,我后面会赋值的,你别瞎操心了,哈哈。

let value:number;
// 以下语句未赋值使用就会抛错
console.logvalue); // ❌在赋值前使用了变量“value”。//使用赋值断言
let value!:number;
console.logvalue); // undefined

联合类型(Union Types

将二种及以上多种类型用 | 隔开的类型称为联合类型

let union: string | number; // union 支持赋值 string 或 numbertype U = string[] | string; // 支持字符串数组或字符串

条件类型(Conditional Types

简单理解就像 js 的 三目运算符.结合代码很好理解。

SomeType extends OtherType ? TrueType : FalseType;

基本使用

interface Animal {live): void;
}
interface Dog extends Animal {woof): void;
}type Example1 = Dog extends Animal ? number : string; // type Example1 = numbertype Example2 = RegExp extends Animal ? number : string; // type Example2 = string

在某些情况下,可以避免写复杂的重载函数。下面是一个重载函数示例

interface IdLabel {id: number;
}
interface NameLabel {name: string;
}function createLabelid: number): IdLabel;
function createLabelname: string): NameLabel;
function createLabelnameOrId: string | number): IdLabel | NameLabel;
function createLabelnameOrId: string | number): IdLabel | NameLabel {throw "unimplemented";
}

利用条件类型改一下

type nameOrId<T extends number | string> = T extends number? IdLabel: NameLabel;
function createLabel<T extends number | number>idOrName: T): NameOrId {thorw "unimplemented";
}

可以看到 nameOrId 做到了 入参类型不同,出参类型自动判断。很明显在只有两种条件的情况下很便捷。

泛型限制

与泛型结合使用时能更好的约束泛型。

type MessageOf<T> = T extends { message: unknown } ? T["message"] : never;type Flatten<T> = T extends any[] ? T[number] : T;

分配条件类型

当我们向条件类型传入联合类型,如果没有使用 [] 会出现映射联合类型的每个成员类型。

type ToArray<T> = T extends any ? T[] : never;
type ToArray2<T> = [T] extends [any] ? T[] : never;type StrArrOrNumArr = ToArray<string | number>; // string[] | number[]
type StrArrOrNumArr2 = ToArray2<string | number>; // string | number)[]

类型别名

类型别名用 type 来给一个类型起个新名字。它只是起了一个新名字,并没有创建新类型。类型别名常用于联合类型。

type personType = {name: string,age: number  
}
let Ethan: personType;type count = number | number[];
function hellovalue: count) {}

类型保护(Type Guards

类型保护是运行时检查某些值,确保某些值在所要类型的范围内。(结合代码示例更方便理解

类型保护有四种方式

1,is自定义类型保护)

function getLengtharg: any): pet is string {return arg.length;
}

2,typeof, 利用判断去做

function getTypeval: any) {if typeof val === "number") return 'number'if typeof val === "string") return 'string'return '啥也不是'
}

3,instanceof, instanceof类型保护*是通过构造函数来细化类型的一种方式

function creatDatedate: Date | string){console.logdate)ifdate instanceof Date){date.getDate)}else {return new Datedate)}
}

4,in

type Fish = { swim: ) => void };
type Bird = { fly: ) => void };function movepet: Fish | Bird) {if "swim" in pet) { // 如果pet里存在 swim方法则为Fish,就游起来return pet.swim);}return pet.fly); // 否则一定为Bird,就飞起来
}

接口(interface

这,是个大玩意儿。

在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。

接口命名一般首字母大写。

基本用法

// 此接口囊括了接口的大部分特性
interface InterA{prop1: string,prop2?: number, // 可选参数readonly prop3: boolean //只读参数readArr: ReadonlyArray<number> //只读数组,一经定义不能被修改birth?: Date; // 生日可选):YYYY-MM-DDhobby?: "football" | "tennis"; // 爱好(可选), 只能为 "football" 或 "tennis"// 以下使用来扩展未知字段的,也就是说此接口除了以上字段还有许多不确定的字段。[prop: string | number]: any; // 索引签名, prop字段必须是 string类型 or number类型。
}

扩展

接口支持 extends 扩展更多的属性

interface InterA {// props
}
// InterB 在 InterA 的基础上扩展了 propb 属性
interface InterB extends InterA {propb: string
}

扩展多类型

interface Colorful {color: string;
}
interface Circle {radius: number;
}interface ColorfulCircle extends Colorful, Circle {}const cc: ColorfulCircle = {color: "red",radius: 42,
};

接口(interface)和类型type)的区别

概念上,interface是一种具体的类型,而type仅是类型的一种别名。

大多数情况下,此两者使用起来差不多。都可以用来描述对象/函数的类型,都可以扩展

这里有一些区别

1,语法

// 定义
type MyTYpe = {name: string;say): void;
}interface MyInterface {name: string;say): void;
}// 扩展
type MyType2 = MyType & {sex:string;
}
let person:MyInterface2 = {name:'ethan',sex:'男',say): void { console.log"hello ts") }
}interface MyInterface2 extends MyInterface {sex: string;
}
let person1:MyInterface2 = {name:'ethan',sex:'男',say): void { console.log"hello ts") }
}

当然,也支持互相扩展

interface MyInterface3 {sex: string;
}type mixType = MyType & MyInterface3
interface mixInterface extends MyType { sex: string }

上面可能是小不同,下面的不同可能让它两在各自场景能各尽其用:

  • type 可以声明基本数据类型别名/联合类型/元组等,而 interface 不行
// 基本类型别名
type UserName = string;
type UserName = string | number;
// 联合类型
type Animal = Pig | Dog | Cat;
type List = [string, boolean, number];
  • interface 能够合并声明,而type 不行
interface Person {name: string
}
interface Person {age: number
}
// 此时Person同时具有name和age属性

泛型(Generics

泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

假设一个场景:一个函数需要入参出参都是 string。可能会这样写

function funcarg:string):string { return arg }

现在需求改了,除了支持 string,还得支持 number,你可能会这样写

function funcarg:string | number):string | number { return arg }

某日,需求又至矣,修修改改无穷尽也??吾心有一马奔腾不止。。。
泛型就是解决这样的问题

基本使用

function func<T>arg:T):T  {return arg;
}
func<string | number>'哈哈哈');
func'哈哈哈');// 不指定类型,ts会自动推断let myIdentity: <U>arg: U) => U = identity;

泛型中的 T 就像一个占位符、或者说一个变量,在使用的时候可以把定义的类型像参数一样传入,它可以原封不动地输出

Array 自身也是个泛型。

interface Array<Type> {length: number;pop): Type | undefined;push...items: Type[]): number;// ...
}

多个参数

function func<T, U>arg:[T,U]):[T,U] {return arg;
}
func"ethan", 18);// ["ethan", 18]

泛型约束

即预先指定该泛型满足某些条件

示例1 基本用法

// 使用extends约束泛型
interface Lengthwise {length: number;
}
function getLength1<T extends Lengthwise>arg:T):T  {console.logarg.length); return arg;
}const str = getLength'ethan')
const arr = getLength[1,2,3])
const obj = getLength{ length: 1 })
const num = getLength11) // ❌类型“number”的参数不能赋给类型“Lengthwise”的参数。

示例2 泛型约束中使用类型参数

function getProperty<T, K extends keyof T>obj: T, key: K) {return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getPropertyx, "a");
getPropertyx, "m"); // ❌类型“"m"”的参数不能赋给类型“"a" | "b" | "c" | "d"”的参数泛型接口

泛型接口

演示 接口与泛型 如何搭配

interface GenericIdentityFn<T> {arg: T): T;
}function identity<T>arg: T): T {return arg;
}let myIdentity: GenericIdentityFn<number> = identity;

泛型类

class GenericNumber<T> {zeroValue: T;add: x: T, y: T) => T;
}let myGenericNumber = new GenericNumber<number>);
myGenericNumber.zeroValue = 0;
myGenericNumber.add = functionx, y) { return x + y; };

泛型别名

type Cart<T> = { list: T[] } | T[];
let c1: Cart<string> = { list: ["1"] };
let c2: Cart<number> = [1];

泛型工具类型

1,typeof,typeof 的主要用途是在类型上下文中获取变量或者属性的类型

let p1 = { name: "ethan", age: 18, isAdult: true };
type People = typeof p1; // 返回的类型一般用type承接取个别名
function getNamep: People): string {return p.name;
}
getNamep1);// typeof p1 编译后
type People = {name: string,age: number,isAdult: boolean,
};

如果p1为嵌套对象也适用。

2, keyof,此操作符是获取某种类型的所有键,返回的是联合类型。

interface Person {name: string;age: number;
}type K1 = keyof Person; // "name" | "age"
type K2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join" 
type K3 = keyof { [x: string]: Person };  // string | number// 也支持基础类型
let K1: keyof boolean; // let K1: "valueOf"
let K2: keyof number; // let K2: "toString" | "toFixed" | "toExponential" | ...
let K3: keyof symbol; // let K1: "valueOf"

3, in,用以遍历枚举类型

type Keys = "a" | "b" | "c"type Obj =  {[p in Keys]: any
} // -> { a: any, b: any, c: any }

4, infer,在条件类型语句中,声明类型变量以使用它。

type ReturnType<T> = T extends ...args: any[]
) => infer R ? R : any; // R承载了返回值的类型

5,extends,为泛型增加约束, 参考之前泛型。

interface Lengthwise {length: number;
}function loggingIdentity<T extends Lengthwise>arg: T): T {console.logarg.length);return arg;
}

6,[Type][key], 索引访问操作符

interface Person {name: string;age: number;
}type Name = Person["name"]; // string

实用程序类型(Utility Types

1,Required,将类型的属性变成必选

Required<Type>

interface Person {name?: string,age?: number
}
const person: Required<Person> = {name: "ethan",age: 18
}

2,Partial,与 Required 相反,将所有属性转换为可选属性

Partial<Type>

interface Person {name: string,age: number
}
type User = Partial<Person>
const shuge: User = {// 输入Person的某些属性name:'ethan'
}

3,Extract,相当于取交集(参1∩参2)

Extract<Type, Union>

type T01 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T11 = Extract<string | number | ) => void), Function>; // ) =>void

4,Exclude,相当于取差集(参1 – 参1∩参2)

Exclude<UnionType, ExcludedMembers>

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

5,Readonly,将数组或对象的所有属性值转换为只读。

Readonly<Type>

interface Todo {title: string;
}
const todo: Readonly<Todo> = {title: "Delete inactive users",
}
todo.title = "Hello"; // ❌无法为“title”赋值,因为它是只读属性。

6,Record, 将参2的类型一一赋给参1的key

Record<Keys, Type>,等同于

type newType = {[key keyof keys]: Type
}
interface CatInfo {age: number;breed: string;
}
type CatName = "miffy" | "boris" | "mordred";
const cats: Record<CatName, CatInfo> = {miffy: { age: 10, breed: "Persian" },boris: { age: 5, breed: "Maine Coon" },mordred: { age: 16, breed: "British Shorthair" },
};

7,Pick,从某些类型里面挑一些属性出来,方便复用

Pick<Type, Keys>

type Person = {name: string;age:number;gender:string
}type P1 = Pick<Person, "name" | "age">; // { name: string; age: number; }

8,Omit,与Pick相反,从某些类型里面剔除一些属性出来,方便复用

Omit<Type, Keys>

interface Person {name: string,age: number,gender: string
}
type P1 = Omit<Person, "age" | "gender"> // { name: string }

9,ReturnType,获取函数返回值类型

ReturnType

type T0 = ReturnType<) => string>; // stringfunction f1): { a: number; b: string };
type T1 = ReturnType<typeof f1>; // { a: number; b: string }type T2 = ReturnType<<T extends U, U extends number[]>) => T>;// number[]

10,NonNullable,去除 null 和 undefined 类型

Parameters<Type>

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

11,Paramenters, 获取函数类型的参数类型,结果是一个元祖(Tuple

Parameters<Type>

type T0 = Parameters<) => string>; // []function f1arg: { a: number; b: string }): void;
type T1 = Parameters<typeof f1>; // [arg: { a: number; b: string }]

12, InstanceType, 获取 构造函数的实例类型

InstanceType<Type>

class C {x = 0;y = 0;
}
type T0 = InstanceType<typeof C>; // C
type T1 = InstanceType<any>; // any

13, Awaited,比较新,获取异步函数中的await或Promises上的.then()方法 返回的类型.

Awaited<Type> | Released: 4.5

type A = Awaited<Promise<string>>; // stringtype B = Awaited<Promise<Promise<number>>>; // numbertype C = Awaited<boolean | Promise<number>>; // number | boolean

我的理解是为了更好的处理 async 函数内 await 的结果类型。

async function foo<T>x: T) {const y: Awaited<T> = await x;// const y: Awaited<T>// const y: T before TS4.5
}

参考
What is the Awaited Type in TypeScript – Stack Overflow

https://www.typescriptlang.org/play

14, 大小写转换

Uppercase<StringType> | 全大写

Lowercase<StringType> | 全小写

Capitalize<StringType> | 首字母写

Uncapitalize<StringType> | 非首字母大写

很好理解,为了更加精确的规定字符串类型的值,值也是一种类型嘛。

type Greeting = "Hello, world";
type ShoutyGreeting = Uppercase<Greeting>;
// type ShoutyGreeting = "HELLO, WORLD"
const helloStr: ShoutyGreeting = "HELLO, WORLD";
const helloStr: ShoutyGreeting = "hello";// ❌不能将类型“"hello"”分配给类型“"HELLO, WORLD"”。type ASCIICacheKey<Str extends string> = `ID-${Uppercase<Str>}`;
type MainID = ASCIICacheKey<"my_app">;
// type MainID = "ID-MY_APP"type Greeting = "Hello, world";
type QuietGreeting = Lowercase<Greeting>;
// type QuietGreeting = "hello, world"type LowercaseGreeting = "hello, world";
type Greeting = Capitalize<LowercaseGreeting>;
// type Greeting = "Hello, world"type UppercaseGreeting = "HELLO WORLD";
type UncomfortableGreeting = Uncapitalize<UppercaseGreeting>;
// type UncomfortableGreeting = "hELLO WORLD"

还有更多的实用工具类,不一一例举了 ,可见 官网

配置文件(tsconfig.json

主要字段

  • extends – 继承配置, 例 “extends”: “./configs/base”,

  • files – 设置要编译的文件的名称;

  • include – 设置需要进行编译的文件,支持路径模式匹配;

  • exclude – 设置无需进行编译的文件,支持路径模式匹配;即使include包含了,但不能排除files的文件

  • 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          // 为装饰器提供元数据的支持}
}

结尾

github 上面有个 类型体操 的项目,适合练习,进阶。

参考了一些网上的博客,甚至有些例子是直接copy, 非常感谢👏👏👏。

5分钟了解 TypeScript – TypeScript 中文手册

https://www.typescriptlang.org/

2022年了,我才开始学 typescript ,晚吗?(7.5k字总结) – 掘金

2022 typescript史上最强学习入门文章2w字) – 掘金

「1.9W字总结」一份通俗易懂的 TS 教程,入门 + 实战! – 掘金

TypeScript 类型操作 – 掘金

查看全文

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dgrt.cn/a/2252415.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传img-xLxjyYGH-1680958995419)/Users/ethanyin/Library/Application%20Support/marktext/images/2023-04-07-17-32-04-image.png)]

重温Typescript

对TS有些生疏了,想着来总结一波,可作为日后工作中的快速参考手册。 TypeScript具有类型系统,且是JavaScript的超集。 它可以编译成普通的JavaScript代码。 TypeScript支持任意浏览器,任意环境,任意系统并且是开源的。 ……

Redis-0408(基础篇完结)

Redis案例-商品秒杀 public static boolean doSecKillString uid, String proid)throws IOException {// 1.uid和proid判断ifuid null||proid null){return false;}// 2.连接jedisJedis jedis new Jedis"192.168.50.105",6379);// 3. 拼接keyString invenKey……

为何不能暂停AI研发?丨杨立昆吴恩达对话实录

北京时间4月8日凌晨0:30,Yann LeCun(杨立昆)和吴恩达针对近期甚嚣尘上的「AI暂停」一事进行了一场深入讨论,讨论主题为「为何为期6个月的AI暂停是完全错误的」。在这场风波中,二人都立场鲜明,明确表态反对暂……

密集场景下的行人跟踪替代算法,头部跟踪算法 | CVPR 2021

一个不知名大学生,江湖人称菜狗 original author: Jacky LiEmail : 3435673055qq.com Time of completion:2023.4.8 Last edited: 2023.4.8 目录
摘要
主要内容
结果
这篇文章是CVPR 2021 的最新论文,文章的标题: 文章的主要内……

蓝易云:Linux系统【Centos7】怎么锁定CPU运行在最高睿频

要锁定Centos7系统的CPU运行在最高睿频,可以通过以下步骤完成:
1.编辑grub配置文件
打开终端,输入以下命令:
sudo vi /etc/default/grub
2.修改CPU频率相关参数
在文件中找到以下参数:
GRUB_CMDLINE_LINUX_DEFAU……

四十五、docker之nginx手动部署前端项目

nginx的作用:
一、静态文件服务器和反向代理django服务
django框架中的静态文件服务只在开发调试时提供服务,当以生产模式运行时需要将静态文件部署到静态文件服务器上。
1. 收集django项目中的静态文件
在配置文件中配置STATIC_ROOT
我们在我的项目……

购物商城订单防重设计方案

背景:在互联网应用中,客户端和服务器之间,通过各类应用向服务器提交表单的时候。通常用户是通过点击提交数据的按钮,来触发客户端上的数据提交操作。 但是由于服务连接、网络延迟等影响,用户可能会出现误操作,比如连续多次点击提交的操作,那么就有可能出现重复订单信息。……

Lombok同时使用@Data和@Builder的问题

问题背景 Lombok使⽤ 同时使⽤Data和Builder ,构建无参构造器报错!编译不通过。如下图: Lombok Data和Builder分别单独分析用法 Lombok使⽤Data可以⽣成⽆参构造和类⾥⾯所有属性的getter/setter⽅法。可以简化我们代码的开发。(……

阿里版ChatGPT:通义千问pk文心一言

随着 ChatGPT 热潮卷起来,百度发布了文心一言、Google 发布了 Bard,「阿里云」官方终于也宣布了,旗下的 AI 大模型“通义千问”正式开启测试! 申请地址:https://tongyi.aliyun.com/
阿里云的 Ai 模型名为“通义千问”……

初识二叉树

树的概念与结构 树是一种非线性的数据结构,它是由n个有限结点组成一个具有层次关系的集合,把它叫做树是因为它看起来像一颗倒挂的树,也就是说它的根朝上,而叶朝下的。 子树之间不能有交集,否则就不是树型结构 比如下面……

深度分析Palantir的投资价值,Palantir2023年将实现强劲反弹?

来源:猛兽财经 作者:猛兽财经 在本文中,猛兽财经将通过对Palantir的股票关键指标、商业模式、盈利能力、影响Palantir2023年股价的关键利好因素等方面,对Palantir进行全面、深度的分析。 Palantir股票的关键指标 自从PalantirPL……

Pandas入门实践2 -数据处理

为了准备数据进行分析,我们需要执行数据处理。在本节中,我们将学习如何清理和重新格式化数据(例如,重命名列和修复数据类型不匹配)、对其进行重构/整形,以及对其进行丰富(例如,离散化……

一、lua基础知识1

一、lua 的数据类型
–类型 a1; –number printtypea)) –number b"HelloWorld"; printtypeb)) –string 两种数据类型 ctrue; printtypec)) –boolean true 或者 false d print; d"HelloWorld"); printtyped)); –function类型 ……

二、lua语言基础2

1.lua的类型有哪些?答:lua的数据类型有:number,string,nil function,table,thread,userdata用户自定义的类型),boolean(布尔类型) 2.什么是尾调用,尾调用有什么优点尾调用:在一个函数的最后一步开始调用另……

quick-cocos2dx-luaUI控件讲解

–MyApp部分 require"config") require"cocos.init") require"framework.init") local MyApp class"MyApp", cc.mvc.AppBase) function MyApp:ctor) MyApp.super.ctorself) end function MyApp:run) cc.FileUti……

quick-cocos2dx lua语言讲解 动作,定时器,触摸事件,工程的类的讲解)

–MainScene部分
— display.newScene 创建一个场景 — 在quick里面我们的控件、精灵 一般是加载到场景上的 local MainScene class"MainScene", function) return display.newScene"MainScene") end) function MainScene:ctor) –创……

使用quick-cocos2dx-lua 实现的小游戏(包含碰撞检测,触屏发子弹)

–主界面local MainScene class"MainScene", function)return display.newScene"MainScene")end)ON true;function MainScene:ctor)local bg cc.Sprite:create"main_background.png");bg:setScale2);bg:setPositiondisplay.cx,display……

cocos2d-js 中scrollview详解

/****
开头的一些废话:
1、多思考,善于思考
2、懂得变通
3、多多查询API首先复制一段 API中的源码:(UIScrollView.js)这段代码可以看出 scrollview
中的容器是一个node,并且他的位置是:代码最后……

cocos2d-js中的回调函数中世界坐标系和节点坐标系的相互转换

世界坐标系和节点坐标系都是OPENGL 坐标系 1、世界坐标系原点就是屏幕的左下角; 2、节点坐标系的原点就是一个节点的左下角; 3、两个坐标系可以通过已经写好的cocosAPI进行想换转换; 4、所有的节点需要转为一个节点上或者是统一的世界坐标系……

通过JavaScript实现漂浮

<html>
<head><meta http-equiv"Content-Type" content"text/html"; charset"gb2312" /><title>漂浮广告</title><style type"text/css">div{position:absolute;}</style>
</head>
&……

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注