如何在特定场景下将TypeScript可选属性设为必填?
如何将TypeScript类型的可选属性在特定场景设为必填?
假设我们有一个表示API响应的TypeScript类型,其中部分属性是可选的:
type Response = { id: string; users?: User[]; // ... 其他可选属性 };
当调用API时传入特定参数,能确定users字段一定会返回,此时希望将该属性设为必填,避免代码中出现data.users可能为undefined的情况(比如使用react-query时)。
最优解决方案:自定义工具类型指定必填属性
TypeScript内置的Required工具类型会将所有可选属性转为必填,无法针对单个属性。我们可以结合Omit和Pick实现一个仅将指定属性设为必填的工具类型:
// 自定义工具类型:将T类型中指定的K属性设为必填 type RequiredKeys<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
使用时直接声明需要转为必填的属性即可,users的类型会沿用原Response中的定义,无需手动指定:
import { useQuery } from '@tanstack/react-query'; import axios from 'axios'; const { data } = useQuery( ['businesses'], async (): Promise<RequiredKeys<Response, 'users'>> => { const { data } = await axios.get(url, { params: queryParams, // 该参数确保users字段必返回 }); return data; } ); // 此时data.users的类型为User[],不再是可选的
其他可选方案
改进泛型方案
如果你愿意修改原Response类型,可以用泛型控制指定属性是否必填,避免调用方手动指定属性类型:
// 泛型T标记users是否必填,默认非必填 type Response<T extends boolean = false> = { id: string; users: T extends true ? User[] : User[] | undefined; // ... 其他属性 };
使用时通过布尔值控制:
- 需要
users必填:Promise<Response<true>> - 默认非必填:
Promise<Response>
不推荐的原泛型方案
你之前尝试的泛型方案需要调用方指定users的类型,不仅不够直观,还会导致原类型中users的定义变化时,所有调用处都需要同步修改,维护成本较高,因此不推荐。
内容的提问来源于stack exchange,提问作者andy mccullough
相关产品推荐
相关产品推荐

