01-any 利 unknown.ts
let a1: unknown = { a: 1 };
let a2: any = { a: 1 };
console.log(a2.a);
02-object 相关加餐.ts
let a: Object = {};
let a1: Object = 123;
let a2: Object = "123";
let a12: object = { name: "123" };
let a13: object = [];
let a14: object = () => {};
let a15: {} = "";
let a16: {} = 123;
let a17: {} = { name: "123" };
let a18: {} = { name: "123" };
03-interface.ts
interface person {
name: string;
age: number;
[key: string]: any;
}
var p: person = { name: "John", age: 30 };
interface a1 {
a2?: string;
}
let a3: a1 = { a2: "123" };
let a4: a1 = {};
interface a5 {
readonly a6: () => boolean;
}
let a7: a5 = {
a6: () => false,
};
interface a8 extends a5 {
a9: string;
}
let a10: a8 = {
a6: () => false,
a9: "123",
};
interface Fn {
(name: string): number[];
}
const fn: Fn = (name: string) => [1, 2, 3];
04-数组.ts
let a1: number[] = [1];
let a2: Array<boolean> = [false];
interface a3 {
name: string;
}
const a4: a3[] = [{ name: "a4" }];
let a5: number[][][] = [[[1]]];
let a6: Array<Array<number>> = [[2]];
let a7: any[] = [1, "2"];
let a8: [string, number] = ["1", 2];
function a9(...arg: string[]) {
console.log(arguments);
let a10: IArguments = arguments;
console.log(a10);
console.log(arg);
}
a9("123");
05-函数扩展.ts
function a1(a: number, b: number): number {
return a + b;
}
console.log(a1(1, 32));
const a2 = (a: number, b: number): number => {
return a + b;
};
console.log(a2(1, 32));
function a3(a?: number, b: number = 10): number {
return a + b;
}
console.log(a3(1, 32));
console.log(a3(1));
console.log(a3());
interface a4 {
name?: string;
age?: number;
}
function a5(a: a4): a4 {
return a;
}
console.log(a5({ name: "xiaoming", age: 18 }));
interface a6 {
user: number[];
add: (this: a6, num: number) => void;
}
let a7: a6 = {
user: [1, 2, 3],
add: function (this: a6, num: number) {
this.user.push(num);
console.log(this.user);
},
};
a7.add(4);
console.log(a7.user);
let a8: number[] = [1, 2, 3];
function a9(add: number[]): number[];
function a9(add: number): number[];
function a9(): number[];
function a9(ids?: number | number[]): number[] {
if (typeof ids === "number") {
return a8.filter((item) => item === ids);
} else if (Array.isArray(ids)) {
a8.push(...ids);
return a8;
} else {
return a8;
}
}
console.log(a9(1));
console.log(a9([1, 2, 3]));
console.log(a9());
06-类型断言,联合类型,交叉类型.ts
let a1: number | string = "10";
let a2 = function (type: number): boolean {
return !!type;
};
let a3 = function (type: number | boolean): boolean {
return !!type;
};
console.log(a3(2));
console.log(a3(false));
interface a4 {
name: string;
age: number;
}
interface a5 {
sex: string;
}
const a6 = (man: a4 & a5): void => {
console.log(man);
};
a6({
name: "123",
age: 12,
sex: "男",
});
function a7(num: number | string): void {
console.log((num as string).length);
}
a7(123);
a7("123");
interface a8 {
name: string;
}
interface a9 {
age: number;
}
let a10 = (type: a8 | a9): void => {
console.log((<a9>type).age);
console.log((type as a9).age);
};
a10({ name: "123" });
a10({ name: "123", age: 12 });
const a11 = (type: any): boolean => {
return type as boolean;
};
console.log(a11("123"));
07-内置对象.ts
let num: Number = new Number(1);
let date: Date = new Date();
let regExp: RegExp = /^[0-9]+$/;
let error: Error = new Error("Error");
let xhr: XMLHttpRequest = new XMLHttpRequest();
let div: HTMLDivElement = document.createElement("div");
let input: HTMLInputElement = document.createElement("input");
let div1: NodeList = document.querySelectorAll("div");
let div2: NodeListOf<HTMLDivElement> = document.querySelectorAll("div");
let arr: Array<string> = ["1", "2", "3"];
08-class.ts
interface a1 {
name: string;
value: number;
}
interface a2 {
options: a1;
init(): void;
}
interface Vnode {}
class a3 implements a2 {
options: a1;
constructor(options: a1) {
this.options = options;
}
init(): void {
let data: Vnode = {};
console.log(1);
}
}
const a4 = new a3({ name: "a", value: 1 });
09-抽象类.ts
abstract class a1 {
name: string;
constructor(name: string) {
this.name = name;
}
getName(): string {
return this.name;
}
abstract init(name: string): void;
}
class a3 extends a1 {
init(name: string) {
console.log(name);
}
}
const a4 = new a3("987");
console.log(a4.getName());
a4.init("123");
10-元组类型.ts
let a: readonly [x: number, y?: boolean] = [1, false];
console.log(a);
type first = (typeof a)["length"];
const a2: first = 1;
const a3: first = 2;
11-枚举类型.ts
enum a1 {
red,
green,
black,
}
console.log(a1.red);
enum a2 {
red = 1,
green,
black,
}
console.log(a2.green);
enum a3 {
red = "red",
green = "green",
black = "black",
}
console.log(a3.green);
enum a4 {
yes = 1,
goof,
no = "no",
}
console.log(a4.no);
console.log(a4.goof);
interface a5 {
red: a4.yes;
}
let a6: a5 = {
red: 1,
};
console.log(a6.red);
const enum a7 {
success,
fail,
}
let code: number = 0;
if (code === a7.success) {
console.log(1);
}
enum a8 {
success,
fail,
}
let code1: number = 0;
if (code1 === a8.success) {
console.log(12);
}
enum a9 {
success,
}
let success: number = a9.success;
console.log(success);
let a10 = a9[success];
console.log(a10);
12.类型推论和类型别名.ts
let str = "123";
type s = string;
let a2: s = "123";
type f = () => void;
let a3: f = function () {};
a3();
type num = 1 extends number ? 1 : 0;
let a4: num = 1;
13-never.ts
function a1(): never {
throw new Error("error");
}
function a2(): never {
while (true) {
switch (true) {
default:
break;
}
}
}
type a3 = void | number | never;
type a5 = "a" | "b" | "c" | "d";
function a4(value) {
switch (value) {
case "a":
console.log("a");
break;
case "b":
console.log("b");
break;
case "c":
console.log("c");
break;
case "d":
console.log("d");
break;
default:
break;
}
}
14-symbol.ts
let a1: Symbol = Symbol("1");
let a2: Symbol = Symbol("2");
console.log(a1);
console.log(a2);
console.log(a1 == a2);
console.log(Symbol.for("a1") === Symbol.for("a1"));
let a3 = {
name: 1,
};
console.log(a3);
Object.getOwnPropertySymbols(a3);
Reflect.ownKeys(a3);
15-生成器和迭代器.ts
function* gen() {
yield Promise.resolve(1);
yield 2;
yield 3;
}
const a1 = gen();
console.log(a1.next());
console.log(a1.next());
console.log(a1.next());
console.log(a1.next());
let set: Set<number> = new Set([1, 2, 3, 1, 1, 2]);
console.log(set);
let map: Map<any, any> = new Map();
let arr = [1, 2, 3, 4, 5];
map.set(arr, "a");
console.log(map.get(arr));
function args() {
console.log(arguments);
}
let list = document.querySelectorAll("li");
const each = (value: any) => {
let it: any = value[Symbol.iterator]();
let next: any = { done: false };
while (!next.done) {
next = it.next();
if (!next.done) {
console.log(next.value);
}
}
};
each(arr);
each(set);
for (const value of arr) {
console.log(value);
}
for (const value of set) {
console.log(value);
}
console.log("------------------------------");
let obj = {
max: 5,
cou: 0,
[Symbol.iterator]() {
return {
max: this.max,
cou: this.cou,
next: () => {
if (this.cou === this.max) {
return { value: undefined, done: true };
} else {
return {
value: this.cou++,
done: false,
};
}
},
};
},
};
for (const value of obj) {
console.log(value);
}
let x = { ...obj };
console.log(x);
16-泛型.ts
function a1(a: number, b: number): Array<number> {
return [a, b];
}
function a2<T>(a: T, b: T): Array<T> {
return [a, b];
}
console.log(a2(1, 2));
console.log(a2("1", "2"));
type a3<T> = string | number | T;
let a4: a3<boolean> = true;
let a5: a3<undefined> = undefined;
let a6: a3<null> = null;
interface a7<T> {
msg: T;
}
let a8: a7<boolean> = {
msg: true,
};
let a9: a7<number> = {
msg: 1,
};
function a10<T = number, K = string>(a: T, b: K): Array<T | K> {
return [a, b];
}
console.log(a10(1, 2));
console.log(a10(1, "2"));
const axios = {
get<T>(url: string): Promise<T> {
return new Promise((res, err) => {
let xhr: XMLHttpRequest = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
res(JSON.parse(xhr.responseText));
} else {
err(xhr.status);
}
}
};
xhr.send(null);
});
},
};
interface Data {
message: string;
code: number;
}
axios.get<Data>("./16.json").then((res) => {
console.log(res.message);
});
16json
{
"code": 200,
"message": "success"
}
17-泛型.ts
function add<T extends number>(a: T, b: T) {
return a + b;
}
add(1, 2);
interface Len {
length: number;
}
function a2<T extends Len>(a: T) {
return a.length;
}
console.log(a2("123"));
let obj = {
name: "123",
sex: "1",
};
function a3<T extends object, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
console.log(a3(obj, "name"));
interface Data {
name: string;
age: number;
sex: string;
}
type Options<T extends object> = {
[K in keyof T]?: T[K];
};
type B = Options<Data>;
18.tsconfig.json
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": "./buildFile",
"diagnostics": true,
"target": "ES5",
"module": "CommonJS",
"outFile": "./app.js",
"lib": ["DOM", "ES2015", "ScriptHost", "ES2019.Array"],
"allowJS": true,
"checkJs": true,
"outDir": "./dist",
"rootDir": "./",
"declaration": true,
"declarationDir": "./file",
"emitDeclarationOnly": true,
"sourceMap": true,
"inlineSourceMap": true,
"declarationMap": true,
"typeRoots": [],
"types": [],
"removeComments":true,
"noEmit": true,
"noEmitOnError": true,
"noEmitHelpers": true,
"importHelpers": true,
"downlevelIteration": true,
"strict": true,
"alwaysStrict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"esModuleInterop": true,
"allowUmdGlobalAccess": true,
"moduleResolution": "node",
"baseUrl": "./",
"paths": {
"jquery": ["node_modules/jquery/dist/jquery.min.js"]
},
"rootDirs": ["src","out"],
"listEmittedFiles": true,
"listFiles": true
}
"include": [
"src/**/*"
],
"exclude": [
"demo.ts"
],
"files": [
"demo.ts"
]
19-namespace.ts
namespace A {
export namespace B {
export namespace C {
export const a = 1;
}
}
}
import AAA = A.B.C;
console.log(AAA.a);
namespace D {
export const a = 1;
}
namespace D {
export const b = 2;
}
console.log(D);
20-三斜线
20-三斜线-1.ts
namespace A {
export const e = 1;
}
console.log(A);
20-三斜线-2.ts
namespace A {
export const fn = () => "a";
}
21-声明文件.ts
22-Mixins 混入.ts
interface Name {
name: string;
}
interface Age {
age: number;
}
interface Sex {
sex: string;
}
let a: Name = { name: "name" };
let b: Age = { age: 10 };
let c: Sex = { sex: "sex" };
let obj = Object.assign({}, a, b, c);
console.log(obj);
class A {
type: boolean;
changeType() {
this.type = !this.type;
}
}
class B {
name: string;
getName(): string {
return this.name;
}
}
class C implements A, B {
type: boolean = false;
name: string = "name";
changeType: () => void;
getName: () => string;
}
mixins(C, [A, B]);
function mixins(curClass: any, itemClass: any[]) {
itemClass.forEach((item) => {
console.log(item);
Object.getOwnPropertyNames(item.prototype).forEach((name) => {
curClass.prototype[name] = item.prototype[name];
});
});
}
let ccc = new C();
ccc.changeType();
console.log(ccc.getName());
23-装饰器 Decorator.ts
import "reflect-metadata";
(function () {
const Base: ClassDecorator = (target) => {
console.log(target);
target.prototype.xiaman = "lgq";
target.prototype.fn = () => {
console.log("123");
};
};
@Base
class Http {}
const http = new Http() as any;
http.fn();
console.log(http.xiaman);
const Name:PropertyDecorator=(target,key)=>{
console.log(target);
console.log(key);
}
class Http2 {
name: string;
@Name
constructor(name: string) {
this.name = 'LGQ';
}
}
const Get = (url: string) => {
const fn: MethodDecorator = (target, key, des) => {
console.log(url);
console.log(target);
console.log(key);
console.log(des);
};
return fn;
};
class Http2 {
@Get("www.baidu.com")
getList(data: any) {
console.log(data);
}
}
const Get4 = (url: string) => {
const fn: MethodDecorator = (target, key, des: PropertyDescriptor) => {
const key = Reflect.getMetaData("key", target);
axios.get(url).then((res) => {
desc.value(key ? res.data[key] : res.data);
});
};
return fn;
};
const Result = (): ParameterDecorator => {
const fn: ParameterDecorator = (target, key, index) => {
Reflect.defineMetadata("key", "result", target);
};
return fn;
};
class Http4 {
@Get4("www.baidu.com")
getList(@Result() data: any) {
console.log(data);
}
}
const Base1 = (name: string) => {
const fn: ClassDecorator = (target) => {
console.log(target);
target.prototype.xiaman = name;
target.prototype.fn = () => {
console.log("123");
};
};
return fn;
};
@Base1("LGQ")
class Http1 {}
const http1 = new Http1() as any;
http1.fn();
console.log(http1.xiaman);
})();
24-rollupTS
rollup.config.js
console.log(process.env);
import ts from "rollup-plugin-typescript2";
import path from "path";
import serve from "rollup-plugin-serve";
import livereload from "rollup-plugin-livereload";
import { terser } from "rollup-plugin-terser";
import resolve from "rollup-plugin-node-resolve";
import repacle from "rollup-plugin-replace";
const isDev = () => {
return process.env.NODE_ENV === "development";
};
export default {
input: "./src/main.ts",
output: {
file: path.resolve(__dirname, "./lib/index.js"),
format: "umd",
sourcemap: true,
},
plugins: [
ts(),
terser({
compress: {
drop_console: !isDev(),
},
}),
repacle({
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
}),
resolve([".js", ".ts"]),
isDev() && livereload(),
isDev() &&
serve({
open: true,
openPage: "/public/index.html",
}),
],
};
package.json
{
"name": "rollupTs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "cross-env NODE_ENV=development rollup -c -w",
"build": "cross-env NODE_ENV=produaction rollup -c"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"cross-env": "^7.0.3",
"rollup-plugin-livereload": "^2.0.5",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-serve": "^1.1.0",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.31.1",
"typescript": "^4.5.5"
}
}
25-webpackTS
package.json
{
"name": "25-webpackts",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack server"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"html-webpack-plugin": "^5.5.3",
"ts-loader": "^9.4.4",
"typescript": "^5.2.2",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
}
}
webpack.config.js
const path = require("path");
const htmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.ts",
mode: "development",
output: {
path: path.resolve(__dirname, "./dist"),
filename: "index.js",
},
stats: "none",
resolve: {
extensions: [".ts", ".js"],
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
module: {
rules: [
{
test: /\.ts$/,
use: "ts-loader",
},
],
},
devServer: {
port: 1988,
proxy: {},
},
plugins: [
new htmlWebpackPlugin({
template: "./public/index.html",
}),
],
};
26-esbuild-swc
package.json
{
"name": "26-esbuild-swc",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@swc/core": "^1.3.85",
"@swc/helpers": "^0.5.2",
"esbuild": "^0.19.3"
}
}
config.ts
import esbuild from "esbuild";
import swc from "@swc/core";
import fs from "node:fs";
await esbuild.build({
entryPoints: ["./index.ts"],
bundle: true,
loader: {
".js": "js",
".ts": "ts",
".jsx": "jsx",
".tsx": "tsx",
},
treeShaking: true,
define: {
"process.env.NODE_ENV": '"production"',
},
plugins: [
{
name: "swc-loader",
setup(build) {
build.onLoad({ filter: /\.(js|ts|tsx|jsx)$/ }, (args) => {
const content = fs.readFileSync(args.path, "utf-8");
const { code } = swc.transformSync(content, {
filename: args.path,
});
return {
contents: code,
};
});
},
},
],
outdir: "dist",
});
27-localstorage
src\enum\index.ts
export enum Dictionaries {
permanent = "permanent",
expire = "__expire__",
}
src\type\index.ts
import { Dictionaries } from "../enum";
export interface StorageCls {
get: <T>(key: Key) => void;
set: <T>(key: Key, value: T, expire: Expire) => void;
remove: (key: Key) => void;
clear: () => void;
}
export interface Data<T> {
value: T;
[Dictionaries.expire]: Expire;
}
export interface Result<T> {
message: string;
value: T | null;
}
export type Key = string;
export type Expire = number | Dictionaries.permanent;
src\index.ts
import { StorageCls, Key, Expire, Data, Result } from "./type";
import { Dictionaries } from "./enum";
class Storage implements StorageCls {
set<T>(key: Key, value: T, expire: Expire = Dictionaries.permanent) {
const data = {
value,
[Dictionaries.expire]: expire,
};
localStorage.setItem(key, JSON.stringify(data));
}
get<T>(key: Key): Result<T | null> {
const value = localStorage.getItem(key);
if (value) {
const data: Data<T> = JSON.parse(value);
const now = new Date().getTime();
if (
typeof data[Dictionaries.expire] == "number" &&
data[Dictionaries.expire] < now
) {
return {
message: `${key},过期了`,
value: null,
};
this.remove(key);
} else {
return {
message: `成功`,
value: data.value,
};
}
} else {
return {
message: "数据无效",
value: null,
};
}
}
remove(key: Key) {
localStorage.removeItem(key);
}
clear() {
localStorage.clear();
}
}
export default Storage;
28-发布订阅模式
interface Evenet {
on: (name: string, fn: Function) => void;
emit: (name: string, ...args: Array<any>) => void;
off: (name: string, fn: Function) => void;
once: (name: string, fn: Function) => void;
}
interface List {
[ket: string]: Array<Function>;
}
class Dispatch implements Evenet {
list: List;
constructor() {
this.list = {};
}
on(name: string, fn: Function) {
const callback = this.list[name] || [];
callback.push(fn);
this.list[name] = callback;
console.log(this.list);
}
off(name: string, fn: Function) {
let eventName = this.list[name];
if (eventName) {
let index = eventName.findIndex((fns) => fns === fn);
eventName.splice(index, 1);
} else {
console.log(name + "--->no event");
}
}
emit(name: string, ...args: Array<any>) {
let eventName = this.list[name];
if (eventName) {
eventName.forEach((fn: Function) => {
fn.apply(this, args);
});
} else {
console.log(name + "--->no event");
}
}
once(name: string, fn: Function) {
let de = (...args: Array<any>) => {
fn.apply(this, args);
};
this.off(name, de);
}
}
const o = new Dispatch();
const fn = (...args: Array<any>) => {
console.log(args);
};
const fn1 = () => {
console.log("fn1");
};
o.on("a", fn1);
o.emit("a", "4564", "456464");
o.once("a", fn);
o.emit("a", "false", "dadadada");
29-proxy
let person = {
name: "John",
age: 24,
};
let personProxy = new Proxy(person, {
get(target, prop, receiver) {
if (target.age <= 18) {
return Reflect.get(target, prop, receiver);
} else {
return "This person is allowed to see this information.";
}
},
});
console.log(personProxy.age);
console.log(Reflect.get(personProxy, "age", personProxy));
const list: Set<Function> = new Set();
const autofun = (cb: Function) => {
if (!list.has(cb)) {
list.add(cb);
}
};
const observable = <T extends object>(params: T) => {
return new Proxy(params, {
set(target, prop, value, receiver) {
console.log("set");
const result = Reflect.set(target, prop, value, receiver);
list.forEach((cb) => cb());
return result;
},
get(target, prop, receiver) {
console.log("get");
return Reflect.get(target, prop, receiver);
},
});
};
const personObersver = observable({
name: "John",
age: 24,
});
autofun(() => {
console.log("变化;了");
});
personObersver.name = "Mike";
personObersver.name = "M111ike";
30-TS 进阶
1-协变,逆变
interface A {
name: string;
age: number;
}
interface B {
name: string;
age: number;
sex: string;
}
let a: A = {
name: "zhangsan",
age: 18,
};
let b: B = {
name: "zhangsan",
age: 18,
sex: "male",
};
a = b;
let fna = (params: A) => {};
let fnb = (params: B) => {};
fnb = fna;
2-weakmap 和 weakset
let set: Set<number> = new Set([1, 2, 7, 7, 10]);
console.log(set);
set.add(100);
console.log(set);
set.delete(100);
console.log(set);
set.clear();
console.log(set);
let obj = {
name: "zfpx",
};
let map: Map<object, any> = new Map();
map.set(obj, "zfpx");
console.log(map);
let a1: any = { name: "123" };
let a2: any = a1;
let weakmap: WeakMap<object, any> = new WeakMap();
weakmap.set(a1, "zfpx");
console.log(weakmap.get(a1));
a1 = null;
a2 = null;
console.log(weakmap.get(a1));
let weakset = new WeakSet([a1, a2]);
console.log(weakset);
3-Pick 和 partail
type Person = {
name: string;
age: number;
text: string;
};
type p1 = Partial<Person>;
type Partial<T> = {
[P in keyof T]?: T[P];
};
type p2 = Pick<Person, "name" | "age">;
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
4-readonly 和 record
type Person = {
name: string;
age: number;
text: string;
};
type R<T> = {
readonly [P in keyof T]: T[P];
};
type PersonR = R<Person>;
type Rec<K extends keyof any, T> = {
[p in K]: T;
};
type K = "A" | "B" | "C";
type B = Rec<K, Person>;
let obj: B = {
A: {
name: "A",
age: 1,
text: "A",
},
B: {
name: "B",
age: 2,
text: "B",
},
C: {
name: "C",
age: 3,
text: "C",
},
};
5-infer 关键字
type Type<T> = T extends Array<infer U> ? U : T;
{
}
type A = Type<string>;
type B = Type<number | string>;
type C = Type<(number | string)[]>;
type T = [string, number, boolean];
type uni = Type<T>;
6-infer 提取元素
type Arr = ["a", "b", "c"];
type First<T extends any[]> = T extends [infer one, ...any[]] ? one : [];
type a = First<Arr>;
type Last<T extends any[]> = T extends [...any[], infer last] ? last : [];
type b = Last<Arr>;
type Pop<T extends any[]> = T extends [...infer Rest, unknown] ? Rest : [];
type c = Pop<Arr>;
type Shift<T extends any[]> = T extends [unknown, ...infer Rest] ? Rest : [];
type d = Shift<Arr>;
7-infer 递归
type Arr = [1, 2, 3];
type ReverArr<T extends any[]> = T extends [infer First, ...infer rest]
? [...ReverArr<rest>, First]
: T;
type Arr1 = ReverArr<Arr>;