[英]Typescript complex type inference
我想为 Rule3 做一个更详细的类型推断
export interface BaseOption {
required?:true;
}
export type Validator = {
[key in string]?: (
val: number,
formData: string,
callback,
props
) => void | Promise<void | Error>;
};
export interface RequiredFunc {
required: (message: string) => void;
}
export type CombineOptions<ExtraOption extends Validator> = ExtraOption &
RequiredFunc;
function Rule<ExtraOption extends Validator>(
options: ExtraOption | BaseOption
) {
return {} as ExtraOption extends BaseOption
? CombineOptions<ExtraOption>
: ExtraOption;
}
// Condition1
const rule1 = Rule({
a() {},
});
rule1.a; // There are code hints in vscode
// Condition2
const rule2 = Rule({ required: true });
rule2.required; // There are code hints in vscode
// Condition3
const rule3 = Rule({
a(f, b) {},
required: true,
});
rule3.required; // There are code hints in vscode
rule3.a; // There are no code hints in vscode
如何获得条件 3 的代码提示。如果我不手动添加 generics,则条件 3 在 vscode 中不起作用。 我的类型推断是错误的方式吗?
一般来说,如果您希望编译器推断类型参数X
,您应该给它一个X
类型的值来推断它。 在您的Rule
function 中,您试图从 X 类型的options
值推断X extends Validator
X | BaseOption
X | BaseOption
,结果不是很好。 一旦options
可分配给BaseOption
,编译器就放弃了更具体地推断X
并退回到Validator
,导致rule2
和rule3
的类型为CombineOptions<Validator>
,这是正确的,但不足以满足您的需求。
如果我们重构使得X
本身是一个扩展Validator | BaseOption
的类型 Validator | BaseOption
并且options
是X
类型,那么推理将正常工作并且编译器不会忘记options
的特定属性:
function Rule<X extends Validator | BaseOption>(options: X): RuleOutput<X> {
return {} as any // impl
}
现在的问题是弄清楚如何将 output 类型RuleOutput<X>
表示为输入类型X
的 function 。 通过阅读您的RequiredFunc
和CombineOptions
类型,看起来您想要做的是 output X
或多或少原样,除非有一个名为required
的键,您希望将该属性类型更改为(message: string) => void
。 这可以通过带有条件类型的映射类型来表示,以检查需要密钥的required
:
type RuleOutput<X> = {
[K in keyof X]:
K extends "required" ? (message: string) => void : X[K]
}
让我们看看它是否有效:
// Condition1
const rule1 = Rule({
a() { },
});
/* const rule1: {
a: () => void;
} */
// Condition2
const rule2 = Rule({ required: true });
/* const rule2: {
required: (message: string) => void;
} */
// Condition3
const rule3 = Rule({
a(f, b) { },
required: true,
});
/* const rule3: {
a: (f: number, b: string) => void;
required: (message: string) => void;
} */
看起来不错。 您的rule1
与之前的类型相同,现在rule2
和rule3
更具体,并且知道作为options
传入的特定键。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.