组合类型在代码中丢失,如何确保data对象的类型安全?
类型组合问题:APIEndpoint与LoginToken组合后data仍为any类型
我有如下函数调用:
myapp.auth(formData).then((/**@type {(import('$lib/types').APIEndpoint & {data?: import('$lib/types').LoginToken}) | null}*/ response) => { if (!response) { console.log('error', 'no response from server'); return; } if (response.status === 200) { // do stuff console.log(response.data); } });
导入的类型定义如下:
export type APIEndpoint = { status: number; error: boolean; data?: any; }; export type LoginToken = { username: string; id: number; isadmin: boolean; permissions: string[]; fullname: string; };
我希望对data对象强制执行类型安全,但悬停查看时它仍显示为data: any,请问我的类型组合方式是否正确?
VS Code中显示的response类型:(APIEndpoint & { data?: LoginToken | undefined; }) | null
VS Code中显示的response.data类型:any
问题原因
你当前的类型组合方式无效,因为APIEndpoint里的data?: any会覆盖交叉类型中data?: LoginToken的定义。TypeScript处理交叉类型时,若两个类型存在同名属性,宽泛的any类型不会被更具体的类型覆盖,反而会“污染”整个属性的类型。
正确解决方法
方法1:泛型重构APIEndpoint类型
这是最推荐的方案,让APIEndpoint支持泛型来指定data的类型:
export type APIEndpoint<T = any> = { status: number; error: boolean; data?: T; }; export type LoginToken = { username: string; id: number; isadmin: boolean; permissions: string[]; fullname: string; };
之后在类型断言时直接使用泛型:
myapp.auth(formData).then((/**@type {import('$lib/types').APIEndpoint<import('$lib/types').LoginToken> | null}*/ response) => { if (!response) { console.log('error', 'no response from server'); return; } if (response.status === 200) { console.log(response.data); // 此时data类型为LoginToken | undefined } });
方法2:用Omit移除原有data属性后交叉
如果不想修改APIEndpoint的原始定义,可以使用Omit工具类型移除原有的data属性,再与包含LoginToken的data属性交叉:
myapp.auth(formData).then((/**@type {(Omit<import('$lib/types').APIEndpoint, 'data'> & {data?: import('$lib/types').LoginToken}) | null}*/ response) => { if (!response) { console.log('error', 'no response from server'); return; } if (response.status === 200) { console.log(response.data); // 此时data类型为LoginToken | undefined } });
两种方法都能让response.data获得正确的类型提示,实现类型安全。
内容的提问来源于stack exchange,提问作者thisjt
相关产品推荐
相关产品推荐

