[Typescript] The partial Inference Problem
Problem for partial inference:
export const makeSelectors = <
TSource,
TSelectors extends Record<string, (source: TSource) => any> = {},
>(
selectors: TSelectors,
) => {
return selectors;
};
interface Source {
firstName: string;
middleName: string;
lastName: string;
}
const selectors = makeSelectors<Source>({
getFullName: (source) =>
`${source.firstName} ${source.middleName} ${source.lastName}`,
getFirstAndLastName: (source) => `${source.firstName} ${source.lastName}`,
getFirstNameLength: (source) => source.firstName.length,
});
So makeSelectors
has type: const makeSelectors: <Source, {}>(selectors: {}) => {}
If remove the generic type:
const selectors = makeSelectors({
getFullName: (source) =>
`${source.firstName} ${source.middleName} ${source.lastName}`,
getFirstAndLastName: (source) => `${source.firstName} ${source.lastName}`,
getFirstNameLength: (source) => source.firstName.length,
});
Then it has type:
/*
const makeSelectors: <unknown, {
getFullName: (source: unknown) => string;
getFirstAndLastName: (source: unknown) => string;
getFirstNameLength: (source: unknown) => any;
}>(selectors: {
getFullName: (source: unknown) => string;
getFirstAndLastName: (source: unknown) => string;
getFirstNameLength: (source: unknown) => any;
}) => {
getFullName: (source: unknown) => string;
getFirstAndLastName: (source: unknown) => string;
getFirstNameLength: (source: unknown) => any;
}
*/
So Problem is If we are using one generic type TSource
in more than one place, like so:
export const makeSelectors = <
TSource,
TSelectors extends Record<string, (source: TSource) => any> = {},
>
Typescript only infer the first generic type, doesn't infer from the second.
Solution could be make it a high order function, each time give one generic type:
import { Equal, Expect } from '../helpers/type-utils';
export const makeSelectors =
<TSource = 'expect to receive a source type'>() =>
<TSelectors extends Record<string, (source: TSource) => any> = {}>(
selectors: TSelectors
) => {
return selectors;
};
interface Source {
firstName: string;
middleName: string;
lastName: string;
}
const selectors = makeSelectors<Source>()({
getFullName: (source) =>
`${source.firstName} ${source.middleName} ${source.lastName}`,
getFirstAndLastName: (source) => `${source.firstName} ${source.lastName}`,
getFirstNameLength: (source) => source.firstName.length,
});
type tests = [
Expect<Equal<typeof selectors['getFullName'], (source: Source) => string>>,
Expect<
Equal<typeof selectors['getFirstAndLastName'], (source: Source) => string>
>,
Expect<
Equal<typeof selectors['getFirstNameLength'], (source: Source) => number>
>
];
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2019-02-27 [Functional Programming] Use Task/Async for Asynchronous Actions
2019-02-27 [Functional Programming] Working with two functors(Applicative Functors)-- Part2 --liftAN
2018-02-27 [CSS3] Create Dynamic Styles with CSS Variables
2017-02-27 [Flow] The Fundamentals of Flow
2017-02-27 [Angular] Some performance tips
2017-02-27 [Ramda] Rewrite if..else with Ramda ifElse
2016-02-27 [Hapi.js] Up and running