如果你想的话
const patterns = [
[String, s => s.length],
[Number, n => n + 1]
];
要具有s
和n
contextually inferred的类型,您必须为patterns
或初始化表达式提供一个类型,其中s
和n
具有适当的上下文.不幸的是,由于您可能希望模式以任何顺序出现,因此您需要的数组元素类型如下所示
type Pattern =
readonly [StringConstructor, (x: string) => number] |
readonly [NumberConstructor, (x: number) => number];
是union type,但not是discriminated union.(因为StringConstructor
和NumberConstructor
不是literal types.)这意味着如果您编写[String, s => s.length]
,编译器不能使用String
来将范围缩小到第一个联合成员,因此不会提供您需要的上下文来推断s
.
因此,如果不以某种方式进行重构,基本上不可能做到这一点.
例如,您可以使模式成为实际的区分并集类型(至少在microsoft/TypeScript#55632固定之前不是tuples):
type Pattern =
{ p: "string", h: (x: string) => number } |
{ p: "number", h: (x: number) => number };
然后它开始工作(只要您使用patterns
类型来提供上下文):
const patterns: Pattern[] = [
{ p: "string", h: s => s.length },
{ p: "number", h: n => n + 1 }
];
但您需要重构match
的实现
function match(
value: string | number,
patterns: readonly Pattern[],
) {
const ctorLookup = { string: String, number: Number }
for (const { p, h } of patterns) {
if (value.constructor = ctorLookup[p]) {
return h(value as never);
}
}
throw new Error("No matching pattern found.");
}
const testingResult = match(123456, patterns);
或者,您可以保留当前的类型,只提供助手函数来生成Pattern
个实例:
type Pattern =
readonly [StringConstructor, (x: string) => number] |
readonly [NumberConstructor, (x: number) => number];
const strPattern = (p: (s: string) => number): Pattern => [String, p];
const numPattern = (p: (s: number) => number): Pattern => [Number, p];
这也是可行的:
const patterns = [strPattern(s => s.length), numPattern(n => n + 1)];
const testingResult = match(123456, patterns);
现在我将停止列举可能性;重点是:要么需要手动注释s
和n
,要么必须以某种方式重构.
Playground link to code个