带有约束的通用打字稿没有密钥

乍得

我正在尝试创建一组对T必须实现并进行接口的泛型进行操作的函数IDocument虽然这似乎通常可行,但似乎TypeScript无法识别T必须具有键IDocument

这是一个最小的示例:

interface IDocument
{
    _id: number;
}

function testGeneric<T>(v: { [P in keyof T]?: T[P] })
{ }

function testConstraint<T extends IDocument>(doc: T)
{
    // this works
    console.log(doc._id);

    // this works
    testGeneric<IDocument>({ _id: doc._id });

    // this fails
    // Argument of type '{ _id: number; }' is not assignable to parameter of type '{ [P in keyof T]?: T[P] | undefined; }'.
    testGeneric<T>({ _id: doc._id });
}

您可以在这里的TypeScript游乐场现场观看

我感到困惑,为什么这不起作用,因为在我的testConstraint函数中好像T总是有一个_id密钥,因为它必须实现IDocument实际上,如果我接受一个T参数并访问该_id属性,它将可以正常工作。

请注意,该testGeneric函数位于我不拥有的库中,因此无法更改该签名。

我在这里做错了什么?我是否需要使用其他约束来表达T必须具有每个键的约束IDocument

贾卡尔兹

原始示例的值类似于{_id: 10}分配给泛型类型(如Partial<T>where)T extends IDocument在这种情况下,您可以证明编译器是正确的,因为有些类型T将扩展IDocument10不是有效属性的地方。这基本上是与该问题相同的问题


在您指定的新范例{_id: doc._id}的泛型类型Partial<T>,其中T extends IDocument仍然产生错误,即使它绝对应该是安全的。编译器是无法验证Pick<T, "_id">是分配给Partial<T>这(涉及)一个未决问题; 编译器目前无法进行必要的类型分析来确保这一点。如果您确定某些内容是安全的(并且已经对它进行了两次和三次检查),但编译器却没有,那么您可能需要使用类型断言

testGeneric<T>({ _id: doc._id } as Partial<T>); // okay now

因此,在实现的内部,testConstraint()您可能需要使用类型声明或等效声明(例如,带有较宽松的实现签名的单个调用签名重载)。


最后,您说过,您实际上想阻止某人拨打电话testConstraint<T>(),但T其属性的属性要IDocument这比T extends IDocumentType更具限制性,并且在TypeScript中表示麻烦,在TypeScript中,属性变窄是子类型化的自然部分。您可以通过使泛型约束包含条件映射类型来做到这一点,如下所示:

function testConstraint<
    T extends IDocument &
    { [K in keyof IDocument]: IDocument[K] extends T[K] ? T[K] : never }>(doc: T): void;
function testConstraint(doc: IDocument) {
    testGeneric({ _id: doc._id });
}

在这里,我们将T约束为IDocument和,并将类型的每个属性IDocument与的对应属性进行比较T如果一个范围T不比一个范围窄,那就IDocument好。否则,约束中的属性将一直缩小never到,T很可能不匹配。

调用签名非常复杂,以至于实现内部的类型确实会使编译器感到困惑。这就是为什么我将其重载,并将实现签名放松为完全非通用的原因。您可能可以对实现进行一些通用的操作,但是要点是,您可能应该根据类型分别对待调用方和实现。

让我们看看该函数的作用:

interface TheVeryFirstDocument extends IDocument {
    _id: 1
}
declare const tv1d: TheVeryFirstDocument;
testConstraint(tv1d); // error!
// --------->  ~~~~~
//  Types of property '_id' are incompatible.
//    Type '1' is not assignable to type 'never'.(

正如我们所希望的那样,这会产生一个错误,而以下内容可以正常工作:

declare const doc: IDocument;
testConstraint(doc); // okay

interface ExtendedDocument extends IDocument {
    title: string;
    numPages: number;
}
declare const xDoc: ExtendedDocument;
testConstraint(xDoc); // okay

好吧,希望能有所帮助;祝好运!链接到代码

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

带有约束的SGDClassifier

来自分类Dev

具有约束的Scala通用类型

来自分类Dev

带有通用参数的打字稿中的工厂

来自分类Dev

选择带有约束ID postgres的

来自分类Dev

带有约束的numpy洗牌

来自分类Dev

为什么带有约束的通用参数类型不能匹配模式,而直接使用约束类型呢?

来自分类Dev

有约束的问题

来自分类Dev

有约束的排序

来自分类Dev

没有约束时sql无法删除约束

来自分类Dev

具有约束的通用方法的重载解析问题

来自分类Dev

如何解决带有约束的自动布局“难题”?

来自分类Dev

带有约束的滚动视图中的iOS Swift Stackview

来自分类Dev

带有约束和RTL的UIScrollView的奇怪行为

来自分类Dev

sql左外连接带有约束列

来自分类Dev

带有约束的 C# 继承泛型类

来自分类Dev

Swift 中带有约束的 SKSpriteNode 的随机向下运动

来自分类Dev

带有约束的 UIViewAnimation 在 Swift 中不起作用

来自分类Dev

以编程方式添加带有约束的 textView

来自分类Dev

SQL Server:增加带有约束的数字

来自分类Dev

Redux传奇使用带有通用函数类型打字稿的Call效果

来自分类常见问题

背包问题变化几乎没有约束

来自分类Dev

Xcode 5-故事板-没有约束

来自分类Dev

我可以使用没有约束的调度吗?

来自分类Dev

背包问题变化几乎没有约束

来自分类Dev

删除对没有约束名称的列的检查

来自分类Dev

打字稿 - 派生相同类型但没有未定义属性的通用

来自分类Dev

当其中一个函数具有带有约束的通用参数时,无法声明两个具有相同名称的函数

来自分类Dev

卸载没有节点的打字稿

来自分类Dev

卸载没有节点的打字稿