TypeScript中type/interface如何设置字段键别名映射数据库短键到全名字段
TS 本身没有提供直接在类型定义里声明字段别名的语法,你可以通过「统一维护映射字典 + 自动推导类型 + 通用转换逻辑」的方案实现全链路自动化,完全不需要手写两套类型和逐个字段赋值的转换函数。
方案1:类型安全的映射转换(推荐)
只需要维护1份短键和长键的对应关系,类型和转换逻辑自动同步,避免漏改、错改问题:
// 唯一需要手动维护的映射字典:短键名 => 应用层长键名 export const LOG_FIELD_MAP = { _id: 'messageId', date: 'date', uid: 'userId', l: 'login', dn: 'displayName', m: 'message', c: 'color', b: 'badges', bi: 'badgeInfo', e: 'emotes', si: 'subInfo', d: 'duration', j: 'joined', p: 'parted', mt: 'messageType' } as const; // 手动维护字段值类型,修改字段时只需要改这里 type LogFieldValueTypes = { _id: string; date: string; uid: number; l: string; dn: string; m: string; c: string; b: Badges; bi: BadgeInfo; e: RawEmotes; si: SubInfo; d: number; j: string[]; p: string[]; mt: MessageType; }; // 自动生成原始数据库返回的Log类型,不需要手动写 export type Log = { [K in keyof LogFieldValueTypes]: LogFieldValueTypes[K] }; // 自动生成应用层用的LogAlias类型,不需要手动写 export type LogAlias = { [K in keyof typeof LOG_FIELD_MAP as typeof LOG_FIELD_MAP[K]]: K extends keyof LogFieldValueTypes ? LogFieldValueTypes[K] : never } & { // 单独处理需要二次转换的subInfo字段 subInfo: SubInfoAlias }; // 通用转换函数,不需要逐个字段赋值 export function convertLog(raw: Log): LogAlias { const res = {} as LogAlias; (Object.keys(LOG_FIELD_MAP) as Array<keyof typeof LOG_FIELD_MAP>).forEach(shortKey => { const longKey = LOG_FIELD_MAP[shortKey]; // 特殊处理需要单独转换的字段 if (shortKey === 'si') { res.subInfo = convertSubInfo(raw.si); return; } res[longKey] = raw[shortKey] as any; }); return res; }
方案2:Proxy零拷贝代理(适合数据量极大的场景)
如果你的Log数据量特别大,不想额外复制一份对象占用内存,可以用Proxy做运行时的键名代理,不需要修改原始对象:
export function createLogProxy(raw: Log): LogAlias { const reverseMap = Object.fromEntries( Object.entries(LOG_FIELD_MAP).map(([short, long]) => [long, short]) ); return new Proxy(raw, { get(target, prop) { if (typeof prop === 'string' && reverseMap[prop]) { return target[reverseMap[prop] as keyof Log]; } return Reflect.get(target, prop); }, set(target, prop, value) { if (typeof prop === 'string' && reverseMap[prop]) { target[reverseMap[prop] as keyof Log] = value; return true; } return Reflect.set(target, prop, value); } }) as LogAlias; }
用这个方案你拿到代理对象后可以直接用长键名读写,底层还是操作原始的短键对象,没有额外的内存开销。
内容的提问来源于stack exchange,提问作者nvh
相关产品推荐
相关产品推荐

