前言
- 为了更好的开发体验,很多时候我们会将string转换为字面量联合类型。而被转换的对象通常也不是写死的,需要进行推断,而没有技巧去做推断很容易又推断出string类型,本文提供几个示例便于触类旁通。
示例
数组转字面量联合
- 数组转字面量联合需要介绍个语法叫as const ,当数组使用as const时,ts推断会变更为字面量而非string类型,这样它认为你不会在后面修改它的引用:
const b = ['aaa', 'bbbn'] as const;
const b = ['aaa', 'bbbn']
- 将其变为字面量联合只要使用
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;
获取对象值的类型转换为字面量联合
type ValueTypeFromMap<T> = {
[k in keyof T]: T[k] }[keyof T]
type a = ValueTypeFromMap<{
name: string, age: number, flag?: boolean }>
const a = {
aaa: 'xxxx',
bbb: 'vvvv',
} as const;
type ValueTypeFromMap<T> = {
[k in keyof T]: T[k] }[keyof T];
type aa = ValueTypeFromMap<typeof a>;
对象属性可选字面量联合
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;
}>;
type a22 = OptionalKeys<{
foo: number; bar?: string }>;
type a33 = OptionalKeys<{
foo: number; flag: boolean }>;
type a44 = OptionalKeys<{
foo?: number; flag?: boolean }>;
type a55 = OptionalKeys<{
}>;
获取对象类型中的必须属性的联合类型
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 }>
type a2 = RequiredKeys<{
foo: number, bar?: string }>
type a3 = RequiredKeys<{
foo: number, flag: boolean }>
type a4 = RequiredKeys<{
foo?: number, flag?: boolean }>
type a5 = RequiredKeys<{
}>