TypeScript调用createBreakpoints时如何挑选类型省略必填传参
TypeScript调用createBreakpoints时省略部分配置键的类型报错解决方案
问题复现
使用Chakra UI提供的createBreakpoints辅助函数时,若希望无需传入全部默认断点配置键,尝试用Pick工具类型筛选需要的键传入泛型:
// Chakra UI 相关源码定义 export interface BaseBreakpointConfig { sm: string md: string lg: string xl: string "2xl"?: string [key: string]: string | undefined } export type Breakpoints<T> = T & { base: "0em" } export const createBreakpoints = <T extends BaseBreakpointConfig>( config: T, ): Breakpoints<T> => { warn({ condition: true, message: [ `[chakra-ui]: createBreakpoints(...) will be deprecated pretty soon`, `simply pass the breakpoints as an object. Remove the createBreakpoint(..) call`, ].join(""), }) return { base: "0em", ...config } } // 测试代码 type Breakpoints = Pick<BaseBreakpointConfig, 'sm' | 'md' | 'lg'> const breakpoints = createBreakpoints<Breakpoints>({ sm: "...", md: "...", lg: "..." });
收到的类型报错原文:Property "xl" is missing in type "Breakpoints" but required in type BaseBreakpointConfig,翻译为:类型"Breakpoints"中缺少必填属性"xl",不符合BaseBreakpointConfig的类型约束。
报错根因
createBreakpoints的泛型约束要求传入的泛型T必须满足extends BaseBreakpointConfig,也就是T必须包含BaseBreakpointConfig里标记为必填的sm/md/lg/xl四个属性。用Pick生成的类型只包含sm/md/lg三个属性,天然不满足泛型约束,自然会触发类型报错。
可行实现方案
方案1:编写类型安全的包装函数(兼容原有调用习惯)
如果需要保留createBreakpoints的调用方式,可以自己写一层包装,修改泛型约束允许传入部分默认断点,同时规避TS类型检查报错:
// 从chakra ui导入原函数 import { createBreakpoints as originalCreateBreakpoints } from '@chakra-ui/theme-tools' // 定义允许传入部分默认断点的配置类型 type PartialBreakpointConfig = Partial<BaseBreakpointConfig> & Record<string, string | undefined> // 重写带正确类型的包装函数 export const createBreakpoints = <T extends PartialBreakpointConfig>(config: T) => { return originalCreateBreakpoints(config as BaseBreakpointConfig) as Breakpoints<T> } // 调用时可以只传需要的断点,不需要强制传xl const breakpoints = createBreakpoints({ sm: "30em", md: "48em", lg: "62em" })
方案2:遵循库官方提示,弃用createBreakpoints调用
从源码的警告信息可以看到,Chakra UI本身已经将createBreakpoints标记为即将废弃的API,官方推荐直接传入断点对象即可,完全不需要套这个函数调用,自然不存在泛型约束的问题:
// 直接定义断点对象,手动补充base属性即可,需要几个断点就传几个 const breakpoints = { base: "0em", sm: "30em", md: "48em", lg: "62em" }
这个方案是官方推荐的最优解,不需要额外写类型适配,也不会用到即将被删除的API。
内容的提问来源于stack exchange,提问作者Toxnyc
相关产品推荐
相关产品推荐

