From 6847d4fbb034cfafffe4d2f42ded6570cba5cb3b Mon Sep 17 00:00:00 2001 From: qiang Date: Sun, 24 Aug 2025 06:03:46 +0800 Subject: [PATCH] chore(hooks): [useLocale] autocomplete locale field keys (#21876) --- packages/components/form/src/types.ts | 72 +------------------------ packages/hooks/use-locale/index.ts | 9 +++- packages/utils/typescript.ts | 78 +++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 73 deletions(-) diff --git a/packages/components/form/src/types.ts b/packages/components/form/src/types.ts index 5b381ed599..4d223b91b5 100644 --- a/packages/components/form/src/types.ts +++ b/packages/components/form/src/types.ts @@ -5,7 +5,7 @@ import type { ValidateFieldsError, } from 'async-validator' import type { ComponentSize } from '@element-plus/constants' -import type { Arrayable } from '@element-plus/utils' +import type { Arrayable, FieldPath } from '@element-plus/utils' import type { MaybeRef } from '@vueuse/core' import type { FormItemProp, @@ -20,76 +20,6 @@ export interface FormItemRule extends RuleItem { trigger?: Arrayable } -type Primitive = null | undefined | string | number | boolean | symbol | bigint -type BrowserNativeObject = Date | FileList | File | Blob | RegExp -/** - * Check whether it is tuple - * - * 检查是否为元组 - * - * @example - * IsTuple<[1, 2, 3]> => true - * IsTuple => false - */ -type IsTuple> = number extends T['length'] - ? false - : true -/** - * Array method key - * - * 数组方法键 - */ -type ArrayMethodKey = keyof any[] -/** - * Tuple index key - * - * 元组下标键 - * - * @example - * TupleKey<[1, 2, 3]> => '0' | '1' | '2' - */ -type TupleKey> = Exclude -/** - * Array index key - * - * 数组下标键 - */ -type ArrayKey = number -/** - * Helper type for recursively constructing paths through a type - * - * 用于通过一个类型递归构建路径的辅助类型 - */ -type PathImpl = V extends - | Primitive - | BrowserNativeObject - ? `${K}` - : `${K}` | `${K}.${Path}` -/** - * Type which collects all paths through a type - * - * 通过一个类型收集所有路径的类型 - * - * @see {@link FieldPath} - */ -type Path = T extends ReadonlyArray - ? IsTuple extends true - ? { - [K in TupleKey]-?: PathImpl, T[K]> - }[TupleKey] // tuple - : PathImpl // array - : { - [K in keyof T]-?: PathImpl, T[K]> - }[keyof T] // object -/** - * Type which collects all paths through a type - * - * 通过一个类型收集所有路径的类型 - * - * @example - * FieldPath<{ 1: number; a: number; b: string; c: { d: number; e: string }; f: [{ value: string }]; g: { value: string }[]; h: Date; i: FileList; j: File; k: Blob; l: RegExp }> => '1' | 'a' | 'b' | 'c' | 'f' | 'g' | 'c.d' | 'c.e' | 'f.0' | 'f.0.value' | 'g.number' | 'g.number.value' | 'h' | 'i' | 'j' | 'k' | 'l' - */ -type FieldPath = T extends object ? Path : never export type FormRules< T extends MaybeRef | string> = string > = Partial< diff --git a/packages/hooks/use-locale/index.ts b/packages/hooks/use-locale/index.ts index 3893e40b1a..c09b1f4004 100644 --- a/packages/hooks/use-locale/index.ts +++ b/packages/hooks/use-locale/index.ts @@ -4,10 +4,15 @@ import English from '@element-plus/locale/lang/en' import type { MaybeRef } from '@vueuse/core' import type { InjectionKey, Ref } from 'vue' +import type { FieldPath } from '@element-plus/utils' import type { Language } from '@element-plus/locale' +export type LocaleKeys = + | Exclude, 'name' | 'el'> + | (string & NonNullable) + export type TranslatorOption = Record -export type Translator = (path: string, option?: TranslatorOption) => string +export type Translator = (path: LocaleKeys, option?: TranslatorOption) => string export type LocaleContext = { locale: Ref lang: Ref @@ -20,7 +25,7 @@ export const buildTranslator = translate(path, option, unref(locale)) export const translate = ( - path: string, + path: LocaleKeys, option: undefined | TranslatorOption, locale: Language ): string => diff --git a/packages/utils/typescript.ts b/packages/utils/typescript.ts index 94d3024724..679190cbcf 100644 --- a/packages/utils/typescript.ts +++ b/packages/utils/typescript.ts @@ -13,3 +13,81 @@ export type Nullable = T | null export type Arrayable = T | T[] export type Awaitable = Promise | T + +type Primitive = null | undefined | string | number | boolean | symbol | bigint +type BrowserNativeObject = Date | FileList | File | Blob | RegExp + +/** + * Check whether it is tuple + * + * 检查是否为元组 + * + * @example + * IsTuple<[1, 2, 3]> => true + * IsTuple => false + */ +type IsTuple> = number extends T['length'] + ? false + : true + +/** + * Array method key + * + * 数组方法键 + */ +type ArrayMethodKey = keyof any[] + +/** + * Tuple index key + * + * 元组下标键 + * + * @example + * TupleKey<[1, 2, 3]> => '0' | '1' | '2' + */ +type TupleKey> = Exclude + +/** + * Array index key + * + * 数组下标键 + */ +type ArrayKey = number + +/** + * Helper type for recursively constructing paths through a type + * + * 用于通过一个类型递归构建路径的辅助类型 + */ +type PathImpl = V extends + | Primitive + | BrowserNativeObject + ? `${K}` + : `${K}` | `${K}.${Path}` + +/** + * Type which collects all paths through a type + * + * 通过一个类型收集所有路径的类型 + * + * @see {@link FieldPath} + */ +type Path = T extends ReadonlyArray + ? IsTuple extends true + ? { + [K in TupleKey]-?: PathImpl, T[K]> + }[TupleKey] // tuple + : PathImpl // array + : { + [K in keyof T]-?: PathImpl, T[K]> + }[keyof T] // object + +/** + * Type which collects all paths through a type + * + * 通过一个类型收集所有路径的类型 + * + * @example + * FieldPath<{ 1: number; a: number; b: string; c: { d: number; e: string }; f: [{ value: string }]; g: { value: string }[]; h: Date; i: FileList; j: File; k: Blob; l: RegExp }> => '1' | 'a' | 'b' | 'c' | 'f' | 'g' | 'c.d' | 'c.e' | 'f.0' | 'f.0.value' | 'g.number' | 'g.number.value' | 'h' | 'i' | 'j' | 'k' | 'l' + */ +export type FieldPath = T extends object ? Path : never