我坚持使用上述打字实现的示例代码.

有没有办法做到这一点,因为我需要在数组内的函数中使用它,即参数

type Pattern<T extends StringConstructor | NumberConstructor> = [T, T extends StringConstructor ? (val: string) => string : (val: number) => number];

function match(
  value: string | number,
  patterns: Pattern<any>[],
) {
  for (const [p, h] of patterns) {
    if (value.constructor === p) {
      return h(value);
    }
  }
  throw new Error("No matching pattern found.");
}

const patterns = [
  [String, (s) => s.length], // Pattern for String
  [Number, (n) => n + 1],   // Pattern for Number
];

//@ts-ignore
const testingResult = match(123456, patterns);

推荐答案

如果你想的话

const patterns = [
  [String, s => s.length],
  [Number, n => n + 1]  
];

要具有sn contextually inferred的类型,您必须为patterns或初始化表达式提供一个类型,其中sn具有适当的上下文.不幸的是,由于您可能希望模式以任何顺序出现,因此您需要的数组元素类型如下所示

type Pattern =
  readonly [StringConstructor, (x: string) => number] |
  readonly [NumberConstructor, (x: number) => number];

union type,但notdiscriminated union.(因为StringConstructorNumberConstructor不是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);

现在我将停止列举可能性;重点是:要么需要手动注释sn,要么必须以某种方式重构.

Playground link to code

Typescript相关问答推荐

Typescript问题和缩减器状态不会在单击时添加用途.属性'状态和调度'不存在于userContextType类型上'|null'

类型脚本不会推断键的值类型

如何正确修复TypScript 4.7到4.8升级中的TS 2345编译错误

类型断言添加到类型而不是替换

在TypeScrip中分配回调时,参数的分配方向与回调本身相反.为什么会这样呢?

ApexCharts条形图未显示最小值.负值

如果数组使用Reaction-Hook-Form更改,则重新呈现表单

Fp-ts使用任务的最佳方法包装选项

在打印脚本中使用泛型扩展抽象类

为什么我的查询钩子返回的结果与浏览器的网络选项卡中看到的结果不同?

刷新页面时,TypeScrip Redux丢失状态

如何将父属性类型判断传播到子属性

正交摄影机正在将渲染的场景切成两半

将对象的属性转换为正确类型和位置的函数参数

如何在Angular 服务中制作同步方法?

是否可以通过映射类型将函数参数约束为预定义类型?

如何在打字角react 式中补齐表格组

如何为带有参数的函数类型指定类型保护?

TS 排除带点符号的键

递归地排除/省略两种类型之间的公共属性