我想有一个类型的形式IA<T>,像

interface IA<T> {
  f: () => T | number;
  x: boolean
}
    

不同的是,当xtrue时,f返回number,而当xfalse时,f返回T.这个是可能的吗?我试过了

interface IA<T> {
 f: (this: IA<T>) => this['x'] extends true ? T : number;
 x: boolean
}

但它不起作用:

const x0: IA<string> = { // error!
  f: () => "hello",
  x: true as const 
}

我的目标是让以下代码正常工作:

if (x0.x === true) {
   x0.f().toUpperCase(); // okay, it's a string
} else {
   x0.f().toFixed(); // okay, it's a number
}

有可能吗?

推荐答案

TypeScript判断一个属性并使其影响其他属性的明显类型的唯一功能是将类型设为discriminated union. 所以让我们把IA<T>变成一个歧视性的婚姻:

type IA<T> =
    { x: true, f: () => T; } |
    { x: false, f: () => number }

(请注意,它必须是type alias而不是interface,但在大多数情况下这不应该是重要的.

这里的x属性是discriminant,使用literal typestruefalse来区分你有哪个联盟成员. 然后,您可以根据需要指定x0值:

const x0: IA<string> = {
    f: () => "hello",
    x: true
} // okay

并执行您预期的缩小范围:

function foo(y: IA<string>) {    
    if (y.x === true) {
        y.f().toUpperCase() // okay
    } else {
        y.f().toFixed() // okay
    }    
}    
foo(x0); // okay

(我把它包装在一个函数中,因为TS足够聪明,注意到x0总是true的情况,因为它是narrows on assignment,所以x0.f().toFixed()失败,因为它知道不能输入分支.

Playground link to code

Typescript相关问答推荐

Typescript:将内部函数参数推断为子对象键的类型

角形标题大小写所有单词除外

当我点击外部按钮时,如何打开Html Select 选项菜单?

typescribe警告,explate—deps,useEffect依赖项列表

webpack错误:模块找不到.当使用我的其他库时,

为什么tsx不判断名称中有"—"的属性?'

泛型函数即使没有提供类型

如何设置绝对路径和相对路径的类型?

如何以Angular 形式显示验证错误消息

在包含泛型的类型脚本中引用递归类型A<;-&B

在实现自定义主题后,Angular 不会更新视图

带下拉菜单的Angular 响应式选项卡

等待用户在Angular 函数中输入

扩展参数必须具有元组类型或传递给REST参数

有没有办法取消分发元组的联合?

创建一个TypeScrip对象并基于来自输入对象的约束定义其类型

在对象数组中设置值

如何按成员资格排除或 Select 元组?

如何使用布尔值构建对象 TYPE,但至少有一个必须为 true

有没有办法将类型与关键更改相匹配?