【typescript】推断字面量联合类型的几种方式

前言

  • 为了更好的开发体验,很多时候我们会将string转换为字面量联合类型。而被转换的对象通常也不是写死的,需要进行推断,而没有技巧去做推断很容易又推断出string类型,本文提供几个示例便于触类旁通。

示例

数组转字面量联合

  • 数组转字面量联合需要介绍个语法叫as const ,当数组使用as const时,ts推断会变更为字面量而非string类型,这样它认为你不会在后面修改它的引用:
const b = ['aaa', 'bbbn'] as const;//readonly ["aaa", "bbbn"]
const b = ['aaa', 'bbbn'] // string[]
  • 将其变为字面量联合只要使用T[number]就行了:
type arrayToLiteral<T extends readonly any[]> = T[number];
type x = arrayToLiteral<typeof b>;
  • 我们也可以使用递归拼接去做这个事:
type arrayToLiteral<T, R = never> = T extends readonly [infer L, ...infer Rest] ? arrayToLiteral<Rest, R | L> : R;
type x = arrayToLiteral<typeof b>;
  • 如果数组里不是string而是对象,需要提取对象里字面量类型也可以这么做,比如:
const a = [{
    
     name: 'aaa' }, {
    
     name: 'bbb' }] as const;
type arrayToLiteral<T, R = never> = T extends readonly [infer L extends {
    
    name:string}, ...infer Rest] ? arrayToLiteral<Rest, R | L['name']> : R;
type x = arrayToLiteral<typeof a>;
  • 第一种方式生成也可以这么修改:
type arrayToLiteral<T extends readonly any[], K extends keyof T[number]> = T[number][K];
type x = arrayToLiteral<typeof a, 'name'>;

对象键转字面量联合

  • 这个大家都知道
const a = {
    
    
  aaa: 'xxxx',
  bbb: 'vvvv',
};
type aaa = keyof typeof a;//"aaa" | "bbb"

获取对象值的类型转换为字面量联合

type ValueTypeFromMap<T> = {
    
     [k in keyof T]: T[k] }[keyof T]
type a = ValueTypeFromMap<{
    
     name: string, age: number, flag?: boolean }>
// string|number|boolean 
  • 如果是需要字面量,加as const即可:
const a = {
    
    
  aaa: 'xxxx',
  bbb: 'vvvv',
} as const;
type ValueTypeFromMap<T> = {
    
     [k in keyof T]: T[k] }[keyof T];
type aa = ValueTypeFromMap<typeof a>;// "xxxx" | "vvvv"

对象属性可选字面量联合

type ExcludeUndefined<T> = {
    
     [K in keyof T]: Exclude<T[K], undefined> };

type OptionalKeys<T, K = keyof T> = K extends keyof T ? (undefined extends ExcludeUndefined<T>[K] ? K : never) : never
type a11 = OptionalKeys<{
    
    
	foo: number | undefined;
	bar?: string;
	flag: boolean;
}>; // bar
type a22 = OptionalKeys<{
    
     foo: number; bar?: string }>; // bar
type a33 = OptionalKeys<{
    
     foo: number; flag: boolean }>; // never
type a44 = OptionalKeys<{
    
     foo?: number; flag?: boolean }>; // foo|flag
type a55 = OptionalKeys<{
    
    }>; // never

获取对象类型中的必须属性的联合类型

type ExcludeUndefined<T> = {
    
    [K in keyof T]:Exclude<T[K],undefined>}
type RequiredKeys<T, K = keyof T> = K extends keyof T ? (undefined extends ExcludeUndefined<T>[K] ? never : K) : never
type a1 = RequiredKeys<{
    
     foo: number | undefined, bar?: string, flag: boolean }>        // foo|flag
type a2 = RequiredKeys<{
    
     foo: number, bar?: string }>                                   // foo
type a3 = RequiredKeys<{
    
     foo: number, flag: boolean }>                                  // foo|flag
type a4 = RequiredKeys<{
    
     foo?: number, flag?: boolean }>                                // never
type a5 = RequiredKeys<{
    
    }>                                                              // never

猜你喜欢

转载自blog.csdn.net/yehuozhili/article/details/126738955