TypeScript泛型优先级

6

更新:问题是TypeScript的一个限制,该问题现在在Typescripts GitHub上: https://github.com/microsoft/TypeScript/issues/47440

我目前有以下代码:

class Table<T,> {
   constructor(records: T[], columns: Column<T>[]) { ... }
}

class Column<T> {
   constructor(name: string, transformer: (item: T) => string) { ... }
   addTooltip(transformer: (item: T) => string): this { ... }
}

class Building {
   constructor (public name: string) {}
}

const buildings = [
   new Building("test"),
   new Building("station")
];

我想创建一个表格,而不必指定T的类型为Building
这目前是可行的,因为typescript可以从buildings数组中推断出类型,并且它能正常工作。即使在Column的transformer中,我仍然能得到类型提示。
const table = new Table(buildings, [
    new Column("Name", building => building.name)
]);

但是当我使用 addTooltip 时,TypeScript 无法确定 T 是什么并且完全崩溃了,因为 Column 假定 Tunknown

const table = new Table(buildings, [
    new Column("Name", building => building.name),
    new Column("Name", building => building.name).addTooltip(t => t.name)
]);

有没有办法告诉TypeScript使用其“记录”构造函数参数的类型作为T的来源,而忽略列认为的T - 而不使用“new Table<Building>(...)”? 我知道我们可以使用“columns:Column < any > []”,但是在Columns中的类型检查将无法工作。

1
看起来你已经达到了类型推断的极限。一旦添加了 addTooltip(),TS 就无法真正找出构造函数的类型参数,因为它必须向后推断。 - biziclop
1
@T.J.Crowder 我想我明白了。基本上,类型推断应该发生的顺序是:Table -> addTooltip() -> Building,但由于addTooltip()依赖于Building,所以这会失败。 - biziclop
1
我有一个版本更接近,但我不认为我能再接近了。https://www.typescriptlang.org/play?#code/MYGwhgzhAEAqYCMQFMA8sA0A+aBvAUNEdMAPYB2EALgE4CuwVpNAFDcmTQCYQBccAbQC6GEqRB0AtpX4BhcVPLoswgJR5oAegBU0AHQHo2zdAC++c6Egx5E6cryFiZSrQZNW5MJOT9qNAEtyAHNRWjBKADNmHxp+FgCqZEl+WHUAXhx-IOD1XC1tAz1jMyciMC4uWFJxKgCAB2UWKgALAL5oW0VUOnIAa3JSAHdyLDCaCIhomlj4xOTUjKzaHNU5BXtYHHz2KjoacmhW9oBuUvN8KyhoACE6AJAuHMdnCn93ZmgWerokAOBoF4fH4ViE8uYLi5qNAEPdHjkYOloAIyoDkENbnCniEWAAiJLUXGqDD4IQnfCXN5UI6IFAAJmgSPI6LgtOQLFhD2xwQgohRxDRGK60jxADlvMhcaJOfCQoycDLuXogchiajmUKNuQxRKpTCsc9MvquTllRLVHoKlUaiA6vVmvKjmafKpSapyUA - Titian Cernicova-Dragomir
这似乎是上下文推断的限制;通常情况下,流程不会通过多个函数调用向后发生;你最多只能得到一个。也许返回 this 的函数可以更加智能地处理,但我猜现在还没有这样的功能。我所能想到的都是解决方法,比如让构造函数接受多个转换器。你想要一个带有解决方法的答案吗?还是一个简单的“不行,对不起”的答案? - jcalz
1
@captain-yossarian 嘿,我一开始就找到了这个(https://github.com/microsoft/TypeScript/issues/47440),所以我认为任何规范讨论都应该在那里进行。 - jcalz
显示剩余4条评论
1个回答

5
我无法告诉你如何实现你真正想要做的事情(也是我真正想要做的事情),但我可以为你提供几个解决方法的选项。
  1. 你可以在Column上拥有一个静态方法,用于执行创建Column和添加工具提示的组合操作。
  2. 你可以在Column上拥有一个静态方法,接受一个Column并向其中添加工具提示。
  3. 你可以拥有一个独立的函数,执行#2中的静态方法所做的操作。
当你这样做时,推断将起作用。

#1

static withTooltip<T>(
    name: string,
    transformer: (item: T) => string,
    tooltipTransformer: (item: T) => string,
): Column<T> {
    const col = new Column(name, transformer);
    col.addTooltip(tooltipTransformer);
    return col;
}

然后构建数组:

const table = new Table(buildings, [
    new Column("Name", building => building.name),
    Column.withTooltip("Name", building => building.name, t => t.name),
]);

#2

static plusTooltip<T>(col: Column<T>, transformer: (item: T) => string): Column<T> {
    col.addTooltip(transformer);
    return col;
}

那么构建数组的过程是:

const table = new Table(buildings, [
    new Column("Name", building => building.name),
    Column.plusTooltip(new Column("Name", building => building.name), t => t.name),
]);

#3

这只是一个函数版本的 #2,而不是静态方法。

Playground 链接


但愿比我更擅长TypeScript的人能提供更好的解决方案。 - T.J. Crowder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接