Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

深入学习 TypeScript 类型体操 #31

Open
Bulandent opened this issue Feb 2, 2024 · 0 comments
Open

深入学习 TypeScript 类型体操 #31

Bulandent opened this issue Feb 2, 2024 · 0 comments

Comments

@Bulandent
Copy link
Owner

模式匹配做提取

数组类型

提取数组第一个元素的类型

type GetFirst<Arr extends unknown[]> =
	Arr extends [infer First, ...unknown[]] ? First : never;

提取数组最后一个元素的类型

type GetLast<Arr extends unknown[]> =
	Arr extends [...unknown[], infer Last] ? Last : never;

取去掉最后一个元素的数组

type PopArr<Arr extends unknown[]> = 
	Arr extends [] ? []
		: Arr extends [...infer Rest, unknown] ? Rest : never;

字符串类型

字符串是否以某个特定字符开头

type StartWidth<Str extends string, Prefix extends String> = 
	Str extends `${Prefix}${string}` ? true : false;

将字符串中某个特定的部分替换成别的字符串

type ReplaceStr<
    Str extends string,
    From extends string,
    To extends string
> = Str extends `${infer Prefix}${From}${infer Suffix}` 
        ? `${Prefix}${To}${Suffix}` : Str;

字符串去除右空格

type TrimStrRight<Str extends string> =
    Str extends `${infer Rest}${' ' | '\n' | '\t'}`
        ? TrimStrRight<Rest> : Str;

函数类型

提取函数参数的类型

type GetParameters<Func extends Function> = 
	Func extends (...args: infer Args) => unknown ? Args : never;

提取函数返回值的类型

type GetReturnType<Func extends Function> = 
	Func extends (...args: any[]) => infer ReturnType
		? ReturnType : never;

构造器

提取构造器参数的类型

type GetInstanceParameters<
    ConstructorType extends new (...args: any) => any
> = ConstructorType extends new (...args: infer ParametersType) => any 
        ? ParametersType : never;

提取构造器返回值类型

type GetInstanceReturnType<
    ConstructorType extends new (...args: any) => any
> = ConstructorType extends new (...args: any) => infer InstanceType 
        ? InstanceType : never;

索引类型

提取 props 中 ref 值的类型

type GetRefProps<Props> =
    'ref' extends keyof Props
        ? Props extends { ref?: infer Value | undefined}
            ? Value : never
        : never;

重新构造做变换

TypeScript 的 type、infer、类型参数声明的变量都不能修改,想对类型做各种变换产生新的类型就需要重新构造。

数组类型的构造

给数组/元组添加新类型

type Push<Arr extends unknown[], Ele> = [...Arr, Ele];

元组重组

type tuple1 = [1,2];
type tuple2 = ['guang', 'dong'];
// 重组成如下的元组
type tuple = [[1, 'guang'], [2, 'dong']];

// 代码实现
type Zip<One extends unknown[], Other extends unknown[]> = 
    One extends [infer OneFirst, ...infer OneRest]
        ? Other extends [infer OtherFirst, ...infer OtherRest]
            ? [[OneFirst, OtherFirst], ...Zip<OneRest, OtherRest>] : []
                : [];

字符串类型的构造

将字符串首字母大写

type CapitalizeStr<Str extends string> = 
    Str extends `${infer First}${infer Rest}`
        ? `${Uppercase<First>}${Rest}` 
        : Str;

将字符串下划线转驼峰

```tstype CamelCase<Str extends string> = Str extends${infer Left}_${infer Right}${infer Rest}`
? `${Left}${Uppercase}${CamelCase}`
: Str;


**删除字符串子串**

```ts
type DropSubStr<Str extends string, SubStr extends string> =
    Str extends `${infer Prefix}${SubStr}${infer Suffix}`
        ? DropSubStr<`${Prefix}${Suffix}`, SubStr>
        : Str;

函数类型的构造

给函数添加一个参数

type AppendArgument<Func extends Function, Arg> = 
    Func extends (...args: infer Args) => infer ReturnType
        ? (...args: [...Args, Arg]) => ReturnType
        : never;

索引类型的构造

索引类型是聚合多个元素的类型。比如 class 和对象都是索引类型。索引类型的元素的类型只能是 string、number 或者 Symbol 等类型。

索引类型的每个元素的类型可以添加修饰符:readonly(只读)、?(可选)。

映射类型语法

type Mapping<Obj extends object> = {
    [Key in keyof Obj]: Obj[Key]
}

用 as 做重映射改变索引类型的 Key 转成大写

type UppercaseKey<Obj extends object> = {
    [Key in keyof Obj as Uppercase<Key & string>]: Obj[Key]
}

因为这里索引的类型可能是 string、number 或 symbol 类型,但是这里转成大写只能是限定为 string。

TS内置高级类型 Record

type Record<K extends string | number | symbol, T> = {[P in K]: T}

UppercaseKey 重写版:用 Record 来约束索引类型而不是 object

type UppercaseKey<Obj extends Record<string, any>> = {
    [Key in keyof Obj as Uppercase<Key & string>]: Obj[Key]
}

给索引类型添加只读的高级类型

type ToReadonly<T> = {
    readonly [Key in keyof T]: T[Key]
}

给索引类型添加可选的高级类型

type ToPartial<T> = {
    [Key in keyof T]?: T[Key]
}

给索引类型去掉只读修饰符

type ToMutable<T> = {
    -readonly [Key in keyof T]: T[Key]
}

给索引类型去掉可选修饰符

type ToRequired<T> = {
    [Key in keyof T]-?: T[Key]
}

返回特定值的类型的索引类型

type FilterByValueType<Obj extends Record<string, any>, ValueType> = {
    [Key in keyof Obj 
        as Obj[Key] extends ValueType ? Key : never]
        : Obj[Key]
}

递归复用做循环

Promise 的递归复用

提取 Promise 值的类型

type DeepPromiseValueType<P extends Promise<unknown>> = 
    P extends Promise<infer ValueType>
        ? ValueType extends Promise<unknown>
            ? DeepPromiseValueType<ValueType>
            : ValueType
        : never;

提取 Promise 值的类型简化版

type DeepPromiseValueType<T> = 
    T extends Promise<infer ValueType>
        ? DeepPromiseValueType<ValueType>
        : never;

数组类型的递归

反转元组

type ReversrArr<Arr extends unknown[]> = 
    Arr extends [infer First, ...infer Rest]
        ? [...ReversrArr<Rest>, First]
        : Arr;

查找元素

type Includes<Arr extends unknown[], FindItem> =
    Arr extends [infer First, ...infer Rest]
        ? IsEqual<First, FindItem> extends true
            ? true
            : Includes<Rest, FindItem>
        : false;
type IsEqual<A, B> =
    (A extends B ? true : false) & (B extends A ? true : false);

删除元素

type RemoveItem<
    Arr extends unknown[],
    Item,
    Result extends unknown[] = []
> = Arr extends [infer First, ...infer Rest] 
    ? IsEqual<First, Item> extends true
        ? RemoveItem<Rest, Item, Result>
        : RemoveItem<Rest, Item, [...Result, First]>
    : Result;
type IsEqual<A, B> =
    (A extends B ? true : false) & (B extends A ? true : false);

构造指定类型的数组

type BuildArray<
    Length extends number,
    Ele = unknown,
    Arr extends unknown[] = []
> = Arr['length'] extends Length
    ? Arr
    : BuildArray<Length, Ele, [...Arr, Ele]>;

字符串类型的递归

替换子串

type ReplaceAll<
    Str extends string,
    From extends string,
    To extends string,
> = Str extends `${infer Left}${From}${infer Right}`
    ? `${Left}${To}${ReplaceAll<Right, From, To>}`
    : Str;

提取字符做联合类型

type StringToUnion<Str extends string> = 
    Str extends `{infer First}${infer Rest}`
        ? First | StringToUnion<Rest>
        : never;

反转字符串

type ReverseStr<Str extends string> = 
    Str extends `${infer First}${infer Rest}`
        ? `${ReverseStr<Rest>}${First}`
        : Str;

对象类型的递归

深度递归

type DeepToReadonly<T extends Record<string, any>> =
    T extends any
        ? {
           readonly [Key in keyof T]:
               T[Key] extends Object
                   ? T[Key] extends Function
                        ? T[Key]
                        : DeepToReadonly<T[Key]>
                    : T[Key]
        }
        : never;

数组长度做计算

数组长度实现加减乘除

加法

type BuildArray<
    Length extends number,
    Ele = unknown,
    Arr extends unknown[] = [],
> = Arr['length'] extends Length
    ? Arr
    : BuildArray<Length, Ele, [...Arr, Ele]>;

type Add<Num1 extends number, Num2 extends number> =
    [...BuildArray<Num1>, ...BuildArray<Num2>]['length'];

减法

type Subtract<Num1 extends number, Num2 extends number> =
    BuildArray<Num1> extends [...BuildArray<Num2>, ...infer Rest]
        ? Rest['length']
        : never;

乘法

type Multiple<
    Num1 extends number,
    Num2 extends number,
    ResultArr extends unknown[] = [],
> = Num2 extends 0
    ? ResultArr['length']
    : Multiple<Num1, Subtract<Num2, 1>, [...ResultArr, ...BuildArray<Num1>]>;

除法

type Divide<
    Num1 extends number,
    Num2 extends number,
    ResultArr extends unknown[] = [],
> = Num1 extends 0
    ? ResultArr['length']
    : Divide<Subtract<Num1, Num2>, Num2, [...ResultArr, unknown]>;

数组长度实现计数

计算字符串长度

type StrLen<
    Str extends string,
    CountArr extends unknown[] = [],
> = Str extends `${string}${infer Rest}`
    ? StrLen<Rest, [...CountArr, unknown]>
    : CountArr['length']

比较2个数值谁更大

type GreaterThan<
    Num1 extends number,
    Num2 extends number,
    CountArr extends unknown[] = [],
> = Num1 extends Num2
    ? false
    : CountArr['length'] extends Num2
        ? true
        : CountArr['length'] extends Num1
            ? false
            : GreaterThan<Num1, Num2, [...CountArr, unknown]>;

实现斐波那契数列

type FibonacciLoop<
    PrevArr extends unknown[], 
    CurrentArr extends unknown[], 
    IndexArr extends unknown[] = [], 
    Num extends number = 1
> = IndexArr['length'] extends Num
    ? CurrentArr['length']
    : FibonacciLoop<CurrentArr, [...PrevArr, ...CurrentArr], [...IndexArr, unknown], Num> 

type Fibonacci<Num extends number> = FibonacciLoop<[1], [], [], Num>;

聚合分散可简化

分布式条件类型

当类型参数为联合类型,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型,这种语法叫做分布式条件类型。

type Union = 'a' | 'b' | 'c';
type UppercaseA<Item extends string> =
    Item extends 'a' ? Uppercase<Item> : Item;

这和联合类型遇到字符串时的处理一样:

type Union = 'a' | 'b';
type str = `${Union}~`
// type str = 'a~' | 'b~';

数组转联合类型

type Arr = ['a', 'b', 'c'];
type UnionArr = Arr[number]; 
// type UnionArr = 'a' | 'b' | 'c';

判断是否是联合类型

type isUnion<A, B = A> =
    A extends A
        ? [B] extends [A]
            ? false
            : true
        : never;

当 A 是联合类型时:

  • A extends A 这种写法是为了触发分布式条件类型,让每个类型单独传入处理的,没别的意义。
  • A extends A 和 [A] extends [A] 是不同的处理,前者是单个类型和整个类型做判断,后者两边都是整个联合类型,因为只有 extends 左边直接是类型参数才会触发分布式条件类型。

BEM

type BEM<
    Block extends string,
    Element extends string[],
    Modifiers extends string[]
> = `${Block}__${Element[number]}--${Modifiers[number]}`

全组合

// A 和 B 的全组合
type Combination<A extends string, B extends string> = 
    A | B | `${A}${B}` | `${B}${A}`
    
// 全组合
type AllCombinations<A extends string, B extends string = A> =
    A extens A
        ? Combination<A, AllCombinations<Exclude<B, A>>>
        : never;

特殊特性要记清

IsAny

any 类型与任何类型的交叉都是 any,也就是 1 & any 结果是 any。

type IsAny<T> = 'a' extends (1 & T) ? true : false;

IsEqual

// 以下这种写法不能判断 isAny,isEqual<'a', any> 会返回 true
type IsEqual<A, B> = (A extends B ? true : false) & (B extends A ? true : false);

// 以下这个可以判断 IsEqual2<'a', any> 会返回 false
type IsEqual2<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2)
    ? true : false;

IsUnion

type IsUnion<A, B> = 
    A extends A
        ? [B] extends [A]
            ? false
            : true
        : never;

IsNever

never 在条件类型中也比较特殊,如果条件类型左边是类型参数,并且传入的是 never,那么直接返回 never。

type TestNever<T> = T extends number ? 1 : 2;
// 如下会返回 never
type result = TestNever<never>; 

// 正确的 IsNever
type IsNever<T> = [T] extends [never] ? true : false;

除此之外,any 在条件类型中也比较特殊,如果类型参数为 any,会直接返回 trueType 和 falseType 的合并。

type TestAny<T> = T extends number ? 1 : 2;
// 如下会返回 1 | 2
type result = TestAny<any>

IsTuple

元组类型的 length 是数字字面量,而数组的 length 是 number。

type IsTuple<T> =
    T extends [...infer Eles]
        ? NotEqual<Ele['length'], number>
        : false;

type NotEqual<A, B> =
    (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2)
    ? false : true;

UnionToIntersection

联合类型转交叉类型。

type UnionToIntersecion<U> =
  (U extends U ? (x: U) => unknown : never) extends (x: infer R) => unknown ? R : never;

GetOptional

提取索引类型中的可选索引。

type GetOptional<Obj extends Record<string, any>> = {
    [
        Key in keyof Obj
            as {} extends Pick<Obj, Key> ? Key : never
    ] : Obj[Key];
}

// Pick 是 TS 内置高级类型
type Pick<T, K extends keyof T> = { [P in K]: T[P]; }

GetRequired

提取索引类型中的非可选索引构造成新的索引类型。

type GetRequired<Obj extends Record<string, any>> = {
    [
        Key in keyof Obj
            as {} extends Pick<Obj, Key> ? never : Key
    ] : Obj[Key];
}

RemoveIndexSignature

过滤掉索引类型中的可索引签名,构造成一个新的索引类型。
索引签名的特性:索引签名不能构造成字符串字面量类型,因为它没有名字,而其他索引可以

type RemoveIndexSignature<Obj extends Record<string, any>> = {
    [
        Key in keyof Obj
            as Key extends `${infer Str}` ? Str : never
    ]: Obj[Key]
}

ClassPublicProps

过滤 class 的 public 属性。
根据特性:keyof 只能拿到 class 的 public 索引,private 和 protected 的索引会被忽略。

type ClassPublicProps<Obj extends Record<string, any>> = {
    [Key in keyof Obj]: Obj[Key]
}

as const

TypeScript 默认推导出来的类型并不是字面量类型。

const obj = {
    a: 1,
    b: 2,
}
type objType = typeof obj;
// type objType = {
//     a: number;
//     b: number
// }

如果想要推到出字面量,就需要用 as const:

const arr = [1, 2, 3];
type arrType = typeof arr;
// type arrType = number[];

const arr2 = [1, 2, 3] as const;
type arrType2 = typeof arr2;
// type arrType2 = readonly [1, 2, 3];

反转3个元素的元组类型,需要加上 readonly 才能匹配成功。

type ReverseArr<Arr> =
    Arr extends readonly [infer A, infer B, infer C]
    ? [C, B, A]
    : never;

练一练

实现 ParseQueryString

将 'a=1&b=2&c=3' 转成 {a: 1, b: 2, c: 3}

type ParseQueryString<Str extends string> =
    Str extends `${infer Param}&${infer Rest}`
        ? MergeParams<ParseParams<Param>, ParseQueryString<Rest>>
        : ParseParam<Str>;

type ParseParams<Param extends string> =
    Param extends `${infer Key}=${infer Value}`
        ? {
            [K in Key]: Value
        } : Record<string, any>;

type MergeParams<
    OneParam extends Record<string, any>,
    OtherParam extends Record<string, any>,
> = {
    [Key in keyof OneParam | keyof OtherParam]:
        Key extends keyof OneParam
            ? Key extends keyof OtherParam
                ? MergeValue<OneParam[Key], OtherParam[Key]>
                : OneParam[Key]
            : Key extends keyof OtherParam
                ? OtherParam[Key]
                : never
}

type MergeValue<One, Other> =
    One extends Other
        ? One
        : Other extends unknown[]
            ? [One, ...Other]
            : [One, Other];

TS 内置的高级类型

Parameters

提取函数类型的参数类型

type Parameters<T extends (...args: any) => any> =
    T extends (...args: infer P) => any
        ? P
        : never;

ReturnType

提取函数类型的返回值类型

type ReturnType<T extends (...args: any) => any> =
    T extends (...args: any) => infer R
        ? R
        : never;

ConstructorParameters

提取构造函数的参数类型

type ConstructorParameters<
    T extends new (...ars: any) => any
> = T extends new (...args: infer P) => any
    ? P
    : never;

InstanceType

提取构造器返回值类型

type InstanceType<
    T extends new (...ars: any) => any
> = T extends new (...ars: any) => infer R
    ? R
    : any;

ThisParameterType

提取函数参数中 this 的类型

type ThisParameterType<T> =
    T extends (this: infer U, ...args: any[]) => any
        ? U
        : unknown;

OmitThisParameter

去除函数参数中的 this 类型,并且返回一个新的类型

type OmitThisParameter<T> =
    unknown extends ThisParameterType<T>
        ? T
        : T extends (...args: infer A) => infer R
            ? ...args: A) => infer R
            : T;

Partial

把索引类型的所有索引变成可选类型

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

Required

把索引类型里可选索引改成必选索引

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

Readonly

索引类型的索引添加只读

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
}

Pick

过滤出指定的索引类型

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
}

Record

创建索引类型

keyof any 会返回 string | number | symbol

type Record<K extends keyof any, T> = {
    [P in K]: T;
}

如果 Record 里的第一个参数是 string | number | symbol,那么创建的就是索引签名索引类型:

type RecordRes = Record<string, number>;
// RecordRes = {
//     [x: string]: number;
// }

Exclude

去掉联合类型中的某些类型,即取差集

联合类型当作为类型参数出现在条件类型左边时,会被分散成单个类型传入,这叫做分布式条件类型。

type Exclude<T, U> = T extends U ? never : T;

Extract

提取联合类型中的某些类型,即取交集

type Extract<T, U> = T extends U ?  T : never;

Omit

去掉某部分索引类型的索引构成新索引类型

type Omit<T, K in keyof any> = Pick<T, EXclude<keyof T, K>>;

Awaited

提取 Promise 的返回值类型

type Awaited<T> = 
    T extends null | undefined
        ? T
        : T extends object & { then(onfulfilled: infer F): any}
            ? F extends ((value, infer V, ...ars: any) => any)
                ? Awaited<V>
                : never
            : T;

NonNullable

判断是否是空类型,即不是 null 或 undefined

type NonNullable<T> = T extends null | unfefined ? never : T;

Uppercase、Lowercase、Capitalize、Uncapitalize

这几个类型分别是实现大写、小写、首字母大写、去掉首字母大写的。
他们的实现是直接用 js 实现的。

综合实战

KebabCaseToCamelCase

'aa-bb-cc' 这种是 KebabCase,而 'aaBbCc' 这种是 CamelCase

type KebabCaseToCamelCase<Str extends string> =
    Str extends `${infer Item}-${infer Rest}`
        ? `${Item}${KebabCaseToCamelCase<Capitalize<Rest>>}`
        : Str;

CamelCaseToKebabCase

type CamelCaseToKebabCase<Str extends string> =
    Str extends `${infer First}${infer Rest}`
        ? First extends Lowercase<First>
            ? `${First}${CamelCaseToKebabCase<Rest>}`
            : `-${Lowercase<First>}${CamelCaseToKebabCase<Rest>}`
        : Str;

Chunk

对数组做分组,比如 1、2、3、4、5 的数组,每两个为 1 组,那就可以分为 1、2 和 3、4 以及 5 这三个 Chunk。

type Chunk<
    Arr extends unknown[],
    ItemLen extends number,
    CurItem extends unknown[] = [],
    Res extends unknown[] = []
> = Arr extends [infer First, ...infer Rest]
    ? CurItem['length'] extends ItemLen
        ? Chunk<Rest, ItemLen, [First], [...Res, CurItem]>
        : Chunk<Rest, ItemLen, [...CurItem, First], Res>
    : [...Res, CurItem]

TupleToNestedObject

根据数组类型,比如 ['a', 'b', 'c'] 的元组类型,再加上值的类型 'xxx',构造出这样的索引类型:

{
    a: {
        b: {
            c: 'xxx'
        }
    }
}
type TupleToNestedObject<
    Tuple extends unknown[],
    ValueType
> = Tuple extends [infer First, ...infer Rest]
    ? {
        [Key in First as Key extends keyof any ? Key : never]:
            Rest extends unknown[]
                ? TupleToNestedObject<Rest, ValueType>
                : ValueType
    }
    : ValueType;

PartialObjectPropByKeys

把一个索引类型的某些 Key 转为 可选的,其余的 Key 不变。

type PartialObjectPropByKeys<
    Obj extends Record<string, any>,
    Key extends keyof any
> = Partial<Pick<Obj, Extract<keyof Obj, Key>>> & Omit<Obj, Key>

type PartialObjectPropByKeys2<
    Obj extends Record<string, any>,
    KeyType extends keyof any
> = {
    [Key in keyof Obj as Key extends KeyType ? Key? : Key]:  Obj[Key]
}

函数重载的三种写法

第一种

function add(a: number, b: number): number;
function add(a: string, b: string): string;
function add(a: any, b: any) {
    return a + b;
}

第二种

interface Func {
    (a: number, b: number): number;
    (a: string, b: string): string;
}
const add: Func = (a: any, b: any) => a + b;

第三种

type Func = ((a: number, b: number) => number) & ((a: string, b: string): string)
const add: Func = (a: any, b: any) => a + b;

UnionToTuple

将联合类型转成元组。

type UnionToTuple<T> = 
    UnionToIntersection<
        T extends any ? () => T : never
    > extends () => infer ReturnType
        ? [...UnionToTuple<Exclude<T, ReturnType>>, ReturnType]
        : [];
        
// 联合转交叉
type UnionToIntersection<U> =
  (U extends U ? (x: U) => unknown : never)  extends (x: infer R) => unknown ? R : never;

join

实现一个类似的效果,将:

const res = join('-')('guang', 'and', 'dong');
// 转成 res = 'guang-and-dong'

join 代码实现

declare function join<
    Delimiter extends string
>(delimiter: Delimiter):
    <Items extends string[]>
        (...parts: Items) => JoinType<Items, Delimiter>;

type JoinType<
    Items extends any[],
    Delimiter extends string,
    Result extends string = ''
> = Items extends [infer First, ...infer Rest]
    ? JoinType<Rest, Delimiter, `${Result}${First & string}-`>
    : RemoveLastDelimiter<Result>;

type RemoveLastDelimiter<Str extends string> = 
  Str extends `${infer Rest}-`
    ? Rest
    : Str;

AllKeyPath

拿到一个索引类型的所有 key 的路径。

type AllKeyPath<Obj extends Record<string, any>> = {
    [Key in keyof Obj]:
        Key extends string
            ? Obj[Key] extends Record<string, any>
                ? Key | `${Key}.${AllKeyPath<Obj[Key]>}`
                : Key
            : never;
}[keyof Obj]

Defaultize

实现这样一个高级类型,对 A、B 两个索引类型做合并,如果是只有 A 中有的不变,如果是 A、B 都有的就变为可选,只有 B 中有的也变为可选。

type Defaultize<A, B> = 
    & Pick<A, Exclude<keyof A, keyof B>>
    & Partial<Pick<A, Extract<keyof A, keyof B>>>
    & Partial<Pick<B, Exclude<keyof B, keyof A>>>

infer extends

枚举值转联合类型

以下会把枚举的数值类型转成字符串类型。

enum Code {
    a = 111,
    b = 222,
    c = 'abc'
}
type res = `${Code}`
// res = '111' | '222' | 'abc'

StrToNum

使用 infer extends 后就就可以正常使用了。

enum Code {
    a = 111,
    b = 222,
    c = 'abc'
}
type StrToNum<Str> = Str extends `${infer Num extends number}`
    ? Num
    : Str;
type res = StrToNum<`${Code}`>
// res = 'abc' | 111 | 222
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant