From 2198cad84f50d0340c737fc94433d787b0ededd5 Mon Sep 17 00:00:00 2001 From: "weicheng.liang" Date: Fri, 14 Jun 2024 16:10:31 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- typings/utils.d.ts | 127 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 typings/utils.d.ts diff --git a/typings/utils.d.ts b/typings/utils.d.ts new file mode 100644 index 00000000..e405f5c5 --- /dev/null +++ b/typings/utils.d.ts @@ -0,0 +1,127 @@ +/** 提取Promise返回值 */ +type UnboxPromise> = T extends Promise ? U : never; +/** 深度提取Promise返回值 */ +type DeepUnboxPromise = T extends Promise ? DeepUnboxPromise : T; +/** 提取构造函数的参数类型 */ +type ConstructorTypes any> = T extends new ( + ...args: infer Args +) => any + ? Args + : never; +/** 为构造函数添加参数类型 */ +type AppendArgument any, Arg> = Func extends ( + ...args: infer Args +) => infer ReturnType + ? (...args: [...Args, Arg]) => ReturnType + : never; +/** 提取元组类型的首个类型 */ +type GetFirst = T extends [infer First, ...rest: unknown[]] ? First : T; +/** 提取构造函数的首个类型 */ +type GetFirstConstructorType = GetFirst>; +/** 为元组类型的push一个类型 */ +type Push = [...T, El]; +/** 为元组类型的unshift一个类型 */ +type Unshift = [El, ...T]; +/** 为元组类型的Zip类型 Zip<[1,3],[2,4]> ==> [[1,2],[3,4]]*/ +type Zip = T extends [infer TItem, ...rest: infer TRest] + ? V extends [infer VItem, ...rest: infer VRest] + ? [[TItem, VItem], ...Zip] + : [] + : []; + +/** 将联合类型转为交叉类型 */ +declare type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ( + k: infer I +) => void + ? I + : never; + +/** eg: type result = StringToUnion<'abc'> 结果:'a'|'b'|'c' */ +type StringToUnion = S extends `${infer S1}${infer S2}` + ? S1 | StringToUnion + : never; + +/** 字符串替换,类似js的字符串replace方法 */ +type Replace< + Str extends string, + From extends string, + To extends string +> = Str extends `${infer Left}${From}${infer Right}` ? `${Left}${To}${Right}` : Str; + +/** 字符串替换,类似js的字符串replaceAll方法 */ +type ReplaceAll< + Str extends string, + From extends string, + To extends string +> = Str extends `${infer Left}${From}${infer Right}` + ? Replace, From, To> + : Str; + +/** eg: type result = CamelCase<'foo-bar-baz'>, 结果:fooBarBaz */ +type CamelCase = S extends `${infer S1}-${infer S2}` + ? S2 extends Capitalize + ? `${S1}-${CamelCase}` + : `${S1}${CamelCase>}` + : S; + +/** eg: type result = StringToArray<'abc'>, 结果:['a', 'b', 'c'] */ +type StringToArray = S extends `${infer S1}${infer S2}` + ? StringToArray + : T; + +/** `RequiredKeys`是用来获取所有必填字段,其中这些必填字段组合成一个联合类型 */ +type RequiredKeys = { + [P in keyof T]: T extends Record ? P : never; +}[keyof T]; + +/** `OptionalKeys`是用来获取所有可选字段,其中这些可选字段组合成一个联合类型 */ +type OptionalKeys = { + [P in keyof T]: object extends Pick ? P : never; +}[keyof T]; + +/** `GetRequired`是用来获取一个类型中,所有必填键及其类型所组成的一个新类型的 */ +type GetRequired = { + [P in RequiredKeys]-?: T[P]; +}; + +/** `GetOptional`是用来获取一个类型中,所有可选键及其类型所组成的一个新类型的 */ +type GetOptional = { + [P in OptionalKeys]?: T[P]; +}; + +/** type result1 = Includes<[1, 2, 3, 4], '4'> 结果: false; type result2 = Includes<[1, 2, 3, 4], 4> 结果: true */ +type Includes = K extends T[number] ? true : false; + +/** eg:type result = MyConcat<[1, 2], [3, 4]> 结果:[1, 2, 3, 4] */ +type MyConcat = [...T, ...U]; +/** eg: type result1 = MyPush<[1, 2, 3], 4> 结果:[1, 2, 3, 4] */ +type MyPush = [...T, K]; +/** eg: type result3 = MyPop<[1, 2, 3]> 结果:[1, 2] */ +type MyPop = T extends [...infer L, infer R] ? L : never; // eslint-disable-line + +type PropType = string extends Path + ? unknown + : Path extends keyof T + ? T[Path] + : Path extends `${infer K}.${infer R}` + ? K extends keyof T + ? PropType + : unknown + : unknown; + +/** + * NestedKeyOf + * Get all the possible paths of an object + * @example + * type Keys = NestedKeyOf<{ a: { b: { c: string } }> + * // 'a' | 'a.b' | 'a.b.c' + */ +type NestedKeyOf = { + [Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object + ? `${Key}` | `${Key}.${NestedKeyOf}` + : `${Key}`; +}[keyof ObjectType & (string | number)]; + +type RecordNamePaths = { + [K in NestedKeyOf]: PropType; +}; From 2dd2c7d3bc1eb22ce2fa8cf587d0995ba2cb7cf7 Mon Sep 17 00:00:00 2001 From: "weicheng.liang" Date: Fri, 14 Jun 2024 17:44:58 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0postinstall?= =?UTF-8?q?=E9=92=A9=E5=AD=90=EF=BC=8C=E7=94=9F=E6=88=90env.d.ts=E6=96=87?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E7=A1=AE=E4=BF=9D=E7=B1=BB=E5=9E=8B=E6=8F=90?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + package.json | 6 ++++- scripts/genEnvTypes.ts | 51 ++++++++++++++++++++++++++++++++++++++++++ typings/env.d.ts | 31 ------------------------- 4 files changed, 57 insertions(+), 32 deletions(-) create mode 100644 scripts/genEnvTypes.ts delete mode 100644 typings/env.d.ts diff --git a/.gitignore b/.gitignore index a3b19c7e..f02b5f04 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules dist typings/auto-imports.d.ts +typings/env.d.ts # local env files .env.local diff --git a/package.json b/package.json index 8c19c664..3a78c5dc 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,8 @@ "description": "a template project for vue3, ViewUIPlus, TypeScript and Vite.", "scripts": { "preinstall": "npx only-allow pnpm", + "postinstall": "npm run gen-env-types", + "gen-env-types": "npx tsx scripts/genEnvTypes.ts || true", "serve": "pnpm dev", "dev": "vite serve", "dev:staging": "vite serve --mode=staging", @@ -42,6 +44,7 @@ "devDependencies": { "@commitlint/cli": "^17.4.2", "@commitlint/config-conventional": "^17.4.2", + "@types/dotenv": "^8.2.0", "@types/events": "^3.0.0", "@types/fabric": "^5.3.0", "@types/fontfaceobserver": "^2.1.3", @@ -53,6 +56,7 @@ "@vitejs/plugin-vue": "^4.1.0", "@vitejs/plugin-vue-jsx": "^3.0.1", "autoprefixer": "^10.4.16", + "dotenv": "^16.4.5", "eslint": "^7.32.0", "eslint-config-prettier": "^8.6.0", "eslint-plugin-prettier": "^4.2.1", @@ -76,4 +80,4 @@ "prettier --write" ] } -} \ No newline at end of file +} diff --git a/scripts/genEnvTypes.ts b/scripts/genEnvTypes.ts new file mode 100644 index 00000000..590f6d89 --- /dev/null +++ b/scripts/genEnvTypes.ts @@ -0,0 +1,51 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +import dotenv from 'dotenv'; + +const directoryPath = path.resolve(__dirname, '..'); + +const targets = ['.env', `.env.${process.env.NODE_ENV || 'development'}`]; + +const envObj = targets.reduce((prev, file) => { + const result = dotenv.parse(fs.readFileSync(path.join(directoryPath, file))); + return { ...prev, ...result }; +}, {}); + +const envType = Object.entries(envObj) + .reduce((prev, [key, value]) => { + return `${prev} + ${key}: '${value}';`; + }, '') + .trim(); + +fs.writeFile( + path.join(directoryPath, 'typings/env.d.ts'), + `/// +// generate by ./scripts/generateEnvTypes.ts +declare interface ImportMetaEnv { + ${envType} +} +interface ImportMeta { + readonly env: ImportMetaEnv; +} +export {}; +`, + (err) => { + if (err) console.log('生成 env.d.ts 文件失败'); + else console.log('成功生成 env.d.ts 文件'); + } +); + +// console.log('envObj:', envObj) + +function formatValue(value) { + let _value; + try { + const res = JSON.parse(value); + _value = typeof res === 'object' ? value : res; + } catch (error) { + _value = `'${value}'`; + } + return _value; +} diff --git a/typings/env.d.ts b/typings/env.d.ts deleted file mode 100644 index 504e329e..00000000 --- a/typings/env.d.ts +++ /dev/null @@ -1,31 +0,0 @@ -/// - -// import { Object } from 'fabric/fabric-impl'; - -declare module '*.vue' { - import type { DefineComponent } from 'vue'; - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types - const component: DefineComponent<{}, {}, any>; - export default component; -} - -declare global { - declare module 'fabric/fabric-impl' {} -} - -export as namespace vfe; -declare module 'vfe' { - export as namespace vfe; - export interface ICanvas extends fabric.Canvas { - c: fabric.Canvas; - editor: Editor; - } -} - -import Editor from '@kuaitu/core'; - -declare global { - interface Window { - editor: Editor; - } -}