TypeScript 字段类型依赖于其他字段

Posted

技术标签:

【中文标题】TypeScript 字段类型依赖于其他字段【英文标题】:TypeScript Field Type Dependent on Other Field 【发布时间】:2022-01-14 09:45:01 【问题描述】:
type Formula =
  | 
      fn: (a: number) => number;
      arg: number;
    
  | 
      fn: (a: () => number) => number;
      arg: () => number;
    ;

在此示例中,我如何键入公式,以便 fn 始终接受 arg 作为参数?我仍然需要像 Formula 这样的类型来表示这两种公式,以防我想将它们混合在一个列表中或创建一个可以返回任何一种类型的函数。

formula1.fn(formula1.arg) // should always work.

换句话说:

    如果argnumber,则fn 应该是(number) => number 如果arg() => number,则fn 应该是(() => number) => number 存在一种涵盖两种类型的公式。
// Just applies formula.fn to formula.arg
const calc = (
  formula: Formula
) => formula.fn(formula.arg);  // formula.arg fails to type check

/*
Argument of type 'number | (() => number)' is not assignable to parameter of type 'number & (() => number)'.
Type 'number' is not assignable to type 'number & (() => number)'.
    Type 'number' is not assignable to type '() => number'.ts(2345)
*/


// Should succeed (fn takes a number and arg is a number)
const num1 = calc(
  fn: (a) => a + 1,
  arg: 3
)

// Should succeed (fn takes a () => number and arg is a () => number)
const num2 = calc(
  fn: (a) => a() + 1,
  arg: () => 3
)

// Should fail because arg is a number and fn expects a () => number parameter
const num3 = calc(
  fn: (a) => a() + 1,
  arg: 4
)

// Should fail because arg is a () => number and fn expects a number parameter
const num4 = calc(
  fn: (a) => a + 1,
  arg: () => 4
)

// It should be possible to build an array
// containing types of formulas.
const formulas: Formula = [
   // plain number formula
  
    fn: a => a + 3,
    arg: 4
  ,
   // () => number formula
  
    fn: a => a() * 2,
    arg: () => 11
  
]

const answers = formulas.map(calc)

谢谢!

【问题讨论】:

【参考方案1】:

你需要一个泛型函数。

type Formula = 
   fn: <T extends (() => number) | number>(a: T) => number;

或者,也许您更喜欢第二个:

type Formula<Arg> = 
      fn: (a: Arg) => number;
      arg: Arg


const calc = <T extends (() => number) | number>(
  formula: Formula<T>
) => formula.fn(formula.arg);

Read more about generic types here

我的理解正确吗?

【讨论】:

这是一个很好的答案,只要 OP 不需要像原来的 Formula 这样的联合类型,比如 this,其中 calc() 拒绝 Formula&lt;()=&gt;number&gt; | Formula&lt;number&gt; 类型的参数. 我想我遇到了这个问题。如果我想制作一个公式列表并全部计算它们(如this),我无法为列表分配类型。 @EugeneWolffe 如果您需要列表或其他用例,请edit 提出您的问题,以便minimal reproducible example 准确显示您遇到的问题,以便答案可以解决这些问题。我很乐意尝试做一些事情,但最好是在问题中列出了所有必要的用例之后。 @jcalz 我尝试澄清问题规范,同时保持最小化。您的示例准确地显示了我正在尝试做的事情,所以如果您有任何建议可以使问题更清楚,请告诉我。谢谢:) 是否有类似this 的问题阻止 TypeScript 允许映射公式的混合列表?

以上是关于TypeScript 字段类型依赖于其他字段的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript 类使用联合类型字段实现接口导致错误 (2322)

我们可以隐藏表单字段依赖于其他字段吗?

Mongoose Typescript 2 Schema 有一个使用其他模式的字段

Django rest框架:序列化依赖于其他状态的额外字段?

如何使唯一数组的自定义验证规则依赖于其他字段 laravel

Django 模型字段依赖于另一个模型字段